ORACLE 索引和MYSQL INNODB 輔助索引對NULL的處理區別
ORACLE 索引和MYSQL INNODB 輔助索引對NULL的處理
我們清楚ORACLE中的b+索引是對鍵值的NULL進行儲存的,以致於我們 IS NULL這種肯定是用不到索引的,
當然這提及的ORACLE表為堆表,索引為單列B+樹索引,(有一種最佳化方式為建立組合索引如create index xx on tab(a,'1')
這樣來保證索引記錄NULL值
這樣DUMP出來為
.....
row#11[7886] flag: ------, lock: 2, len=12
col 0; NULL
col 1; len 1; (1): 31
col 2; len 6; (6): 01 00 00 d5 00 0a
....
記錄了NULL值)
而且在某些情況下,比如
select count(b) from tab ;
這種如果b列沒有顯示的申明為not null屬性也是用不到的,必須加上not null或者在where條件中加上
b is not null。
很明顯這些問題都是ORACLE索引並不儲存對null值進行儲存
而mysql innodb 不同如果 is null可定用到b+索引的,那麼說明INNODB 是儲存的NULL值的。
本文將透過對ORACLE INDEX進行BLOCK DUMP和對innodb 輔助索引進行內部訪問來證明,
為了簡單起見我還是建立兩個列的表如下:
ORACLE:
create table test (a int,b int,primary key(a));
create index b_index on test(b);
mysql innodb:
create table test (a int,b int,primary key(a),key(b));
插入一些值:
insert into test values(1,1);
insert into test values(5,NULL);
insert into test values(3,1);
insert into test values(4,2);
insert into test values(10,NULL);
insert into test values(7,4);
insert into test values(8,5);
insert into test values(11,NULL);
insert into test values(20,6);
insert into test values(21,6);
insert into test values(19,NULL);
insert into test values(16,7);
我們透過檢視執行計劃:
ORACLE:
SQL> select /*+ index(test,b_index)*/ * from test where b is null;
A B
---------- ----------
5
10
11
19
Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 104 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TEST | 4 | 104 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
mysql:
mysql> explain select * from test where b is null;
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+
| 1 | SIMPLE | test | NULL | ref | b | b | 5 | const | 4 | 100.00 | Using where; Using index |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
為了起到強制作用ORACLE使用HINT來指定索引,但是由於根本用不到所以ORACLE已經忽略,MYSQL innodb已經用到。
接下來我們來分析其內部結構:
ORACLE:
SQL> SELECT OBJECT_ID FROM DBA_OBJECTS where object_name='B_INDEX';
OBJECT_ID
----------
75905
SQL> oradebug setmypid
Statement processed.
SQL> oradebug tracefile_name
/home/oracle/diag/rdbms/mytest/mytest/trace/mytest_ora_2996.trc
SQL> alter session set events 'immediate trace name treedump level 75905';
Session altered.
檢視trace檔案
核心內容:
*** 2016-11-16 22:45:55.053
----- begin tree dump
leaf: 0x10000c3 16777411 (0: nrow: 8 rrow: 8)
----- end tree dump
因為B+樹只有一個節點就是DBA 16777411,我們單獨DUMP這個塊
進行DBA換算
SQL> select dbms_utility.data_block_address_file(16777411),
2 dbms_utility.data_block_address_block(16777411) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(16777411)
----------------------------------------------
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(16777411)
-----------------------------------------------
4
195
進行BLOCK DUMP:
SQL> oradebug setmypid
Statement processed.
SQL> oradebug tracefile_name
/home/oracle/diag/rdbms/mytest/mytest/trace/mytest_ora_3009.trc
SQL> alter system dump datafile 4 block 195;
檢視TRACE 檔案:
塊資料:
row#0[8020] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 00 b7 00 00
row#1[8008] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 00 b7 00 02
row#2[7996] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 03
col 1; len 6; (6): 01 00 00 b7 00 03
row#3[7984] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 05
col 1; len 6; (6): 01 00 00 b7 00 05
row#4[7972] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 06
col 1; len 6; (6): 01 00 00 b7 00 06
row#5[7960] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 07
col 1; len 6; (6): 01 00 00 b7 00 08
row#6[7948] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 07
col 1; len 6; (6): 01 00 00 b7 00 09
row#7[7936] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 08
col 1; len 6; (6): 01 00 00 b7 00 0b
有8記錄,其順序按照b列大小排序及COL 0,COL2是ROWID
注意COL是number型別有ORACLE自己演算法
演算法參考:
http://blog.itpub.net/7728585/viewspace-2128563/
其實這裡壓根就沒有儲存4行NULL行因為我們一共12行,dump出來只有8行
下面看看MYSQL INNODB:
因為選擇了2列的表我的程式可以直接跑出索引結果:
詳細參考:
http://blog.itpub.net/7728585/viewspace-2126344/
這裡跑一下
./mysqlblock test.ibd -d
current read blocks is : 0 --This Block is file space header blocks!
current read blocks is : 1 --This Block is insert buffer bitmap blocks!
current read blocks is : 2 --This Block is inode blocks!
current read blocks is : 3 --This Block is data blocks( index pages)!
current read blocks is : 4 --This Block is data blocks( index pages)! --這裡是我們需要檢視的輔助索引的塊
[root@testmy test]# ./a.out test.ibd 4
Index_no is:117
find first one record!
B:5,A:-2147483616-->
B:10,A:-2147483592-->
B:11,A:-2147483568-->
B:19,A:-2147483544-->
B:1,A:1-->
B:1,A:3-->
B:2,A:4-->
B:4,A:7-->
B:5,A:8-->
B:6,A:20-->
B:6,A:21-->
B:7,A:16-->
B:5,A:-2147483616--> insert into test values(5,NULL);
B:10,A:-2147483592--> insert into test values(10,NULL);
B:11,A:-2147483568--> insert into test values(11,NULL);
B:19,A:-2147483544--> insert into test values(19,NULL);
我們可以看到INNODB確實記錄了NULL值,但是這是如何記錄的?
我們上面跑的結果看到是一個很大的負數,但是這個程式並沒有考慮NULL值,也就是
全部是not null的情況下正確,
其實不要忘記了行頭的 NULL辨識點陣圖:
nullable field bitmap (1 bit * null field)
每個NULL值佔用一個一位(bit),如果不滿一個位元組按一個位元組算,如果不存在NULL值
至少佔用一個位元組為00。
接下來我們還是要看看這個位,老辦法而進行開啟(無語累)
看了2進位制後如下:
010000180026 實際這6個位元組的第一個位元組就是NULL 點陣圖及01
80000005
實際上MYSQL INNODB也沒有真正的儲存欄位的NULL值,而是至少儲存這行的了主鍵值(rowid)
,在行頭記錄了一個點陣圖來表示(ORACLE壓根沒有這行的ROWID資訊)
01點陣圖實際上就是 0000 0001 表示第一個欄位為NULL,
那麼使用索引就簡單了,簡單掃描相對的欄位點陣圖標示位1的就出來了。
所以官方文件才有:
For both BTREE and HASHindexes, comparison of a key part with a constant value is a range condition
when using the =, <=>, IN(), IS NULL, or IS NOT NULL operators.
這樣的說法,這IS NULL 對ORACLE是不成立的。
最後我們來做一下測試來證明NULL點陣圖這個位元組是否對應的是欄位順序:
為了簡單起見建立3個表
create table test10 (a int,b int,c int,d int,primary key(a),key(b,c,d));
create table test11 (a int,b int,c int,d int,primary key(a),key(b,c,d));
create table test12 (a int,b int,c int,d int,primary key(a),key(b,c,d));
mysql> insert into test10 values(1,NULL,1,NULL);
Query OK, 1 row affected (0.02 sec)
mysql> insert into test11 values(1,1,NULL,NULL);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test12 values(1,NULL,NULL,1);
Query OK, 1 row affected (0.01 sec)
對於key(b,c,d)來說
b是第一個欄位NULL為0001,c為第二個欄位NULL為0010,d為第三個欄位NULL為0100
我們來看看這個位元組,按照我們的推論第一個應該為0000 0101,第二個應該為0000 0110,第三個應該為0000 0011
也就是05,06,03
不出所料下面是二進位制顯示分別為:
05000010fff28000000180000001
06000010fff28000000180000001
03000010fff28000000180000001
可見推論正確。
下面終結一下2種資料庫索引對NULL值處理的不同
1、ORACLE B+所以壓根沒有儲存NULL行的ROWID,沒有任何NULL資訊。那麼涉及到任何NULL的查詢都不能使用索引
(注意這裡不包含文章開頭那種組合索引,指的是B+單列索引,更不包含IOT表。
今天在發這個文章的時候一哥們不知道為什麼會扯到IOT,畢竟ORACLE中常用
的HEAP TABLE這種無序的儲存方式來儲存資料,而不像INNODB本生就是IOT
關於IOT參考我的部落格:
http://blog.itpub.net/7728585/viewspace-1820365/)
2、MYSQL INNODB 儲存了NULL行的資訊,至少主鍵是有的,但是NULL值的表示方法是使用一個BITMAP 點陣圖位元組(不一定是一個位元組)
點陣圖位元組的順序代表了欄位的順序,所以使用is null可以使用到索引。
再說點題外話,我記錄部落格僅僅是習慣,因為學習ORACLE很多年了也寫了很多年了,將部落格作為一種筆記,因為技術這個東西今天你研究學習的很深入,
過幾天不用肯定就忘了,如果留下部落格可以查閱就方便複習一些,當然也記錄一些問題和經驗給大家,近1年多才開始學習MYSQL同時學習一些底層的程式設計
技術,當然學習MYSQL避免不了和ORACLE比較,我想用這種學習方法來加深映像,當然水平有限確實可能有一些問題,也歡迎指出。
我們清楚ORACLE中的b+索引是對鍵值的NULL進行儲存的,以致於我們 IS NULL這種肯定是用不到索引的,
當然這提及的ORACLE表為堆表,索引為單列B+樹索引,(有一種最佳化方式為建立組合索引如create index xx on tab(a,'1')
這樣來保證索引記錄NULL值
這樣DUMP出來為
.....
row#11[7886] flag: ------, lock: 2, len=12
col 0; NULL
col 1; len 1; (1): 31
col 2; len 6; (6): 01 00 00 d5 00 0a
....
記錄了NULL值)
而且在某些情況下,比如
select count(b) from tab ;
這種如果b列沒有顯示的申明為not null屬性也是用不到的,必須加上not null或者在where條件中加上
b is not null。
很明顯這些問題都是ORACLE索引並不儲存對null值進行儲存
而mysql innodb 不同如果 is null可定用到b+索引的,那麼說明INNODB 是儲存的NULL值的。
本文將透過對ORACLE INDEX進行BLOCK DUMP和對innodb 輔助索引進行內部訪問來證明,
為了簡單起見我還是建立兩個列的表如下:
ORACLE:
create table test (a int,b int,primary key(a));
create index b_index on test(b);
mysql innodb:
create table test (a int,b int,primary key(a),key(b));
插入一些值:
insert into test values(1,1);
insert into test values(5,NULL);
insert into test values(3,1);
insert into test values(4,2);
insert into test values(10,NULL);
insert into test values(7,4);
insert into test values(8,5);
insert into test values(11,NULL);
insert into test values(20,6);
insert into test values(21,6);
insert into test values(19,NULL);
insert into test values(16,7);
我們透過檢視執行計劃:
ORACLE:
SQL> select /*+ index(test,b_index)*/ * from test where b is null;
A B
---------- ----------
5
10
11
19
Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 104 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TEST | 4 | 104 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
mysql:
mysql> explain select * from test where b is null;
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+
| 1 | SIMPLE | test | NULL | ref | b | b | 5 | const | 4 | 100.00 | Using where; Using index |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
為了起到強制作用ORACLE使用HINT來指定索引,但是由於根本用不到所以ORACLE已經忽略,MYSQL innodb已經用到。
接下來我們來分析其內部結構:
ORACLE:
SQL> SELECT OBJECT_ID FROM DBA_OBJECTS where object_name='B_INDEX';
OBJECT_ID
----------
75905
SQL> oradebug setmypid
Statement processed.
SQL> oradebug tracefile_name
/home/oracle/diag/rdbms/mytest/mytest/trace/mytest_ora_2996.trc
SQL> alter session set events 'immediate trace name treedump level 75905';
Session altered.
檢視trace檔案
核心內容:
*** 2016-11-16 22:45:55.053
----- begin tree dump
leaf: 0x10000c3 16777411 (0: nrow: 8 rrow: 8)
----- end tree dump
因為B+樹只有一個節點就是DBA 16777411,我們單獨DUMP這個塊
進行DBA換算
SQL> select dbms_utility.data_block_address_file(16777411),
2 dbms_utility.data_block_address_block(16777411) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(16777411)
----------------------------------------------
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(16777411)
-----------------------------------------------
4
195
進行BLOCK DUMP:
SQL> oradebug setmypid
Statement processed.
SQL> oradebug tracefile_name
/home/oracle/diag/rdbms/mytest/mytest/trace/mytest_ora_3009.trc
SQL> alter system dump datafile 4 block 195;
檢視TRACE 檔案:
塊資料:
row#0[8020] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 00 b7 00 00
row#1[8008] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 00 00 b7 00 02
row#2[7996] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 03
col 1; len 6; (6): 01 00 00 b7 00 03
row#3[7984] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 05
col 1; len 6; (6): 01 00 00 b7 00 05
row#4[7972] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 06
col 1; len 6; (6): 01 00 00 b7 00 06
row#5[7960] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 07
col 1; len 6; (6): 01 00 00 b7 00 08
row#6[7948] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 07
col 1; len 6; (6): 01 00 00 b7 00 09
row#7[7936] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 08
col 1; len 6; (6): 01 00 00 b7 00 0b
有8記錄,其順序按照b列大小排序及COL 0,COL2是ROWID
注意COL是number型別有ORACLE自己演算法
演算法參考:
http://blog.itpub.net/7728585/viewspace-2128563/
其實這裡壓根就沒有儲存4行NULL行因為我們一共12行,dump出來只有8行
下面看看MYSQL INNODB:
因為選擇了2列的表我的程式可以直接跑出索引結果:
詳細參考:
http://blog.itpub.net/7728585/viewspace-2126344/
這裡跑一下
./mysqlblock test.ibd -d
current read blocks is : 0 --This Block is file space header blocks!
current read blocks is : 1 --This Block is insert buffer bitmap blocks!
current read blocks is : 2 --This Block is inode blocks!
current read blocks is : 3 --This Block is data blocks( index pages)!
current read blocks is : 4 --This Block is data blocks( index pages)! --這裡是我們需要檢視的輔助索引的塊
[root@testmy test]# ./a.out test.ibd 4
Index_no is:117
find first one record!
B:5,A:-2147483616-->
B:10,A:-2147483592-->
B:11,A:-2147483568-->
B:19,A:-2147483544-->
B:1,A:1-->
B:1,A:3-->
B:2,A:4-->
B:4,A:7-->
B:5,A:8-->
B:6,A:20-->
B:6,A:21-->
B:7,A:16-->
B:5,A:-2147483616--> insert into test values(5,NULL);
B:10,A:-2147483592--> insert into test values(10,NULL);
B:11,A:-2147483568--> insert into test values(11,NULL);
B:19,A:-2147483544--> insert into test values(19,NULL);
我們可以看到INNODB確實記錄了NULL值,但是這是如何記錄的?
我們上面跑的結果看到是一個很大的負數,但是這個程式並沒有考慮NULL值,也就是
全部是not null的情況下正確,
其實不要忘記了行頭的 NULL辨識點陣圖:
nullable field bitmap (1 bit * null field)
每個NULL值佔用一個一位(bit),如果不滿一個位元組按一個位元組算,如果不存在NULL值
至少佔用一個位元組為00。
接下來我們還是要看看這個位,老辦法而進行開啟(無語累)
看了2進位制後如下:
010000180026 實際這6個位元組的第一個位元組就是NULL 點陣圖及01
80000005
實際上MYSQL INNODB也沒有真正的儲存欄位的NULL值,而是至少儲存這行的了主鍵值(rowid)
,在行頭記錄了一個點陣圖來表示(ORACLE壓根沒有這行的ROWID資訊)
01點陣圖實際上就是 0000 0001 表示第一個欄位為NULL,
那麼使用索引就簡單了,簡單掃描相對的欄位點陣圖標示位1的就出來了。
所以官方文件才有:
For both BTREE and HASHindexes, comparison of a key part with a constant value is a range condition
when using the =, <=>, IN(), IS NULL, or IS NOT NULL operators.
這樣的說法,這IS NULL 對ORACLE是不成立的。
最後我們來做一下測試來證明NULL點陣圖這個位元組是否對應的是欄位順序:
為了簡單起見建立3個表
create table test10 (a int,b int,c int,d int,primary key(a),key(b,c,d));
create table test11 (a int,b int,c int,d int,primary key(a),key(b,c,d));
create table test12 (a int,b int,c int,d int,primary key(a),key(b,c,d));
mysql> insert into test10 values(1,NULL,1,NULL);
Query OK, 1 row affected (0.02 sec)
mysql> insert into test11 values(1,1,NULL,NULL);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test12 values(1,NULL,NULL,1);
Query OK, 1 row affected (0.01 sec)
對於key(b,c,d)來說
b是第一個欄位NULL為0001,c為第二個欄位NULL為0010,d為第三個欄位NULL為0100
我們來看看這個位元組,按照我們的推論第一個應該為0000 0101,第二個應該為0000 0110,第三個應該為0000 0011
也就是05,06,03
不出所料下面是二進位制顯示分別為:
05000010fff28000000180000001
06000010fff28000000180000001
03000010fff28000000180000001
可見推論正確。
下面終結一下2種資料庫索引對NULL值處理的不同
1、ORACLE B+所以壓根沒有儲存NULL行的ROWID,沒有任何NULL資訊。那麼涉及到任何NULL的查詢都不能使用索引
(注意這裡不包含文章開頭那種組合索引,指的是B+單列索引,更不包含IOT表。
今天在發這個文章的時候一哥們不知道為什麼會扯到IOT,畢竟ORACLE中常用
的HEAP TABLE這種無序的儲存方式來儲存資料,而不像INNODB本生就是IOT
關於IOT參考我的部落格:
http://blog.itpub.net/7728585/viewspace-1820365/)
2、MYSQL INNODB 儲存了NULL行的資訊,至少主鍵是有的,但是NULL值的表示方法是使用一個BITMAP 點陣圖位元組(不一定是一個位元組)
點陣圖位元組的順序代表了欄位的順序,所以使用is null可以使用到索引。
再說點題外話,我記錄部落格僅僅是習慣,因為學習ORACLE很多年了也寫了很多年了,將部落格作為一種筆記,因為技術這個東西今天你研究學習的很深入,
過幾天不用肯定就忘了,如果留下部落格可以查閱就方便複習一些,當然也記錄一些問題和經驗給大家,近1年多才開始學習MYSQL同時學習一些底層的程式設計
技術,當然學習MYSQL避免不了和ORACLE比較,我想用這種學習方法來加深映像,當然水平有限確實可能有一些問題,也歡迎指出。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2128571/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- NULL在oracle和mysql索引上的區別NullOracleMySql索引
- Mysql innodb引擎和myisam引擎使用索引區別MySql索引
- MySQL的btree索引和hash索引的區別MySql索引
- MySQL單列索引和組合索引的區別MySql索引
- MySQL Hash索引和B-Tree索引的區別MySql索引
- MySQL InnoDB 索引MySql索引
- Mysql InnoDB B+樹索引和雜湊索引的區別? MongoDB 為什麼使用B-樹?MySql索引MongoDB
- MySQL單列索引和組合索引的區別介紹MySql索引
- mysql innodb索引高度MySql索引
- 主鍵索引 (聚集索引) 和普通索引 (輔助索引) 的區別索引
- MySQL中is not null和!=null和<>null的區別MySqlNull
- MySQL中InnoDB引擎對索引的擴充套件MySql索引套件
- 探索MySQL的InnoDB索引失效MySql索引
- 【Mysql】InnoDB 中的聚簇索引、二級索引、聯合索引MySql索引
- Mysql innodb引擎(一)緩衝和索引MySql索引
- 淺析InnoDB引擎的索引和索引原理索引
- [轉]聚集索引和非聚集索引的區別索引
- 使用聚集索引和非聚集索引的區別索引
- MySQL中IS NULL、IS NOT NULL、!=不能用索引?胡扯!MySqlNull索引
- 【索引】Oracle之不可見索引和虛擬索引的比對索引Oracle
- MySQL InnoDB的索引擴充套件MySql索引套件
- MySQL InnoDB搜尋索引的StopwordsMySql索引
- MySQL的InnoDB索引原理詳解MySql索引
- mysql索引型別Normal,Unique,Full Text區別以及索引方法Btree,Hash的區別MySql索引型別ORM
- SQL Server 聚集索引和非聚集索引的區別SQLServer索引
- Mysql索引的使用 - 組合索引 + 範圍條件的處理MySql索引
- 隨筆:MySQL中'' ' ' NULL在Innodb儲存的區別MySqlNull
- 【Mysql】InnoDB 中的 B+ 樹索引MySql索引
- MYSQL中的普通索引,主健,唯一,全文索引區別MySql索引
- 搞懂MySQL InnoDB B+樹索引MySql索引
- 索引全掃描和索引快速全掃描的區別索引
- Mysql 中 MyISAM 和 InnoDB 的區別MySql
- MySQL索引的型別MySql索引型別
- NULL與索引Null索引
- Oracle對錶、索引和簇的分析Oracle索引
- sqlserver索引重建和索引重組的區別和操作方法SQLServer索引
- 索引與null(一):單列索引索引Null
- 索引與null(二):組合索引索引Null