索引與null(二):組合索引
這篇文章主要討論組合索引與null的關係。
二、組合索引
SQL> create table t(a int,b int,c int);
Table created
SQL> create unique index idx_t on t(b,c);
Index created
SQL> select * from t;
A B C
---------- ---------- ----------
1 1 1
2 2
3 3
4
SQL>
1、索引是否索引null值
SQL> analyze table t compute statistics for table for all indexes for all indexed columns;
Table analyzed
SQL> select index_name,table_name,num_rows from user_indexes where table_name='T';
INDEX_NAME TABLE_NAME NUM_ROWS
------------------------------ ------------------------------ ----------
IDX_T T 3
--索引包含了3行,顯然,欄位不全為空的行可以被索引。
把索引的block dump出來,主要部分如下:
-------------------------------------------------------------------
row#0[8022] flag: -----, lock: 0, data:(6): 01 80 74 52 00 00
col 0; len 2; (2): c1 02
col 1; len 2; (2): c1 02
row#1[8010] flag: -----, lock: 0, data:(6): 01 80 74 52 00 01
col 0; len 2; (2): c1 03
col 1; NULL
row#2[7998] flag: -----, lock: 0, data:(6): 01 80 74 52 00 02
col 0; NULL
col 1; len 2; (2): c1 04
------------------------------------------------------------------
--可見,唯一性索引並不包含rowid
2、null和null是否相等
SQL> select * from t;
A B C
---------- ---------- ----------
1 1 1
2 2
3 3
4
SQL> insert into t values(5,2,null);
insert into t values(5,2,null)
ORA-00001: 違反唯一約束條件 (SUK.IDX_T)
--在(b,c)上建有唯一性索引,這裡違反了唯一性約束是不是表示(2,null)=(2,null),也就是null=null呢?其實這樣理解是錯誤的,在oracle中,null=null、null<>null永遠都不會成立,oracle在處理唯一性約束時也不例外。在這裡例子中,null=null只是表象,從這個表象得到的結論是錯誤的。()
--我們知道,oracle索引不索引空值,唯一行索引索引值由列值組成,不包含rowid,在(2,null)這行中,索引的鍵值是2(null不被索引),如果再查入一行(2,null),鍵值也為2,違反了唯一性所以約束,也就是上例報錯的真正原因。
--實際上,在唯一性組合索引中,如果兩行中相同的列的值相同,則會違反唯一性約束,如:
(2,null)和(2,null)會違反唯一性約束,但
(2,null)和(null,2)不會違反唯一性約束。
3、為什麼hints不起作用
我們做一系列與單列索引時類似的測試:
測試一、> select /*+ index(t idx_t) */ * from t;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=4 Bytes=36)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=4 Bytes=36)
--hint不起作用
測試二、> select /*+ index(t idx_t) */ * from t where b is not null;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=18)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=2 Bytes=
18)
2 1 INDEX (FULL SCAN) OF 'IDX_T' (UNIQUE) (Cost=1 Card=2)
--指明組合索引的其中一個列不為空後可以走索引
測試三、> select /*+ index(t idx_t) */ * from t where b=1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=9)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=
9)
2 1 INDEX (RANGE SCAN) OF 'IDX_T' (UNIQUE) (Cost=1 Card=1)
--指明組合索引其中一列為某一個值後可以走索引
測試四、> select /*+ index(t idx_t) */ * from t where c=null;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=18)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=2 Bytes=
18)
2 1 INDEX (FULL SCAN) OF 'IDX_T' (UNIQUE) (Cost=1 Card=2)
--指明組合索引的其中一列為某一個值後可以走索引(這裡把null看成一個常數)
測試五、> select /*+ index(t idx_t) */ * from t where b=1 and c=1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=9)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=1 Card=1 Bytes=
9)
2 1 INDEX (UNIQUE SCAN) OF 'IDX_T' (UNIQUE)
--同時指定b、c的值後可以走索引
測試六、> select /*+ index(t idx_t) */ * from t where b is null and c is not null;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=9)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=
9)
2 1 INDEX (RANGE SCAN) OF 'IDX_T' (UNIQUE) (Cost=1 Card=1)
--指定組合索引中的一列為空,另一列不能為空,可以走索引
測試八、
SQL> delete from t where b is null or c is null;
3 rows deleted
SQL> alter table t modify b not null;
Table altered
> select /*+ index(t idx_t) */ * from t;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=4 Bytes=36)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=4 Bytes=
36)
2 1 INDEX (FULL SCAN) OF 'IDX_T' (UNIQUE) (Cost=1 Card=4)
--為組合索引的其中一個欄位加上not null約束可以走索引
測試九、> alter table t modify b null;
表已更改。
> alter table t modify c not null;
表已更改。
> select /*+ index(t idx_t) */ * from t where b is null and c is null;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=2 Bytes=18)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=2 Bytes=
18)
2 1 INDEX (RANGE SCAN) OF 'IDX_T' (UNIQUE) (Cost=1 Card=2)
--組合索引的其中一個欄位限定了不能為空,即使條件都是is null也可以走索引
--oracle在執行sql的時候會檢視錶的設計,然後得到的表的結構資訊忽略一些無效的調教,上例就是這樣。
--這也說明了網上常說的col is null不能用到索引的說法是不完全準確的,在某些條件下,col is null也可以用到索引。
4、用hints強制使用索引的前提
假如有組合索引(a,b):
(1)在想要用到的組合索引對應的其中一個或者多個欄位上有not null約束就可以用到索引。如果索引列其中一個或者多個有not null約束,無論條件怎麼寫都可能用到索引(包括a is null and b is null)
(2)如果索引列沒有not null約束,在where條件中限定了用到的索引對應的其中一個或者多個列為not null就可以用到索引,如a is not null(甚置 a is not null and b is null 也可以用到索引)
(3)如果索引列沒有not null約束,且在條件中沒有指明索引列為not null,在where條件中包含了用到的索引對應的一個或者多個列與其他值的比較(除a is null外)可以用到索引。甚至 a=1 and b is null 也可以用到索引
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/231499/viewspace-63751/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 索引與null(一):單列索引索引Null
- mysql組合索引,abc索引命中MySql索引
- mysql的組合索引MySql索引
- 索引設計(組合索引適用場景)索引
- 【Mysql】InnoDB 中的聚簇索引、二級索引、聯合索引MySql索引
- MySQL學習筆記:組合索引-索引下推MySql筆記索引
- MySQL 組合索引不生效MySql索引
- MySQL中IS NULL、IS NOT NULL、!=不能用索引?胡扯!MySqlNull索引
- SQLServer索引優化(3):對於建組合索引的要求SQLServer索引優化
- 為什麼索引無法使用is null和is not null索引Null
- Oracle vs PostgreSQL,研發注意事項(12) - NULL與索引OracleSQLNull索引
- MySQL 二 索引MySql索引
- MySQL索引(二):建索引的原則MySql索引
- MySQL組合索引和最左匹配原則MySql索引
- oracle組合索引什麼情況下生效?Oracle索引
- MySQL複合索引MySql索引
- mysql 索引合併MySql索引
- [20231024]NULL值在索引的情況.txtNull索引
- oracle複合索引介紹(多欄位索引)Oracle索引
- 資料庫聚簇索引——not null條件對唯一鍵索引成為聚簇索引的影響資料庫索引Null
- MySQL學習筆記:組合索引-最左原則MySql筆記索引
- oracle重建索引(二)Oracle索引
- Phoenix 二級索引索引
- Phoenix二級索引索引
- NULL列時,如何使得IS NULL或者IS NOT NULL可以使用索引來提高查詢效率Null索引
- 聯合索引和多個單列索引使用中的索引命中情況及索引建立原則索引
- MySQL的聯合索引MySql索引
- MySQL複合索引探究MySql索引
- in、exists與索引索引
- order by與索引索引
- NULL在oracle和mysql索引上的區別NullOracleMySql索引
- MySql如何使用索引(二)MySql索引
- 阿里面試題: (a,b,c)組合索引, 查詢語句select...from...where a=.. and c=..走索引嗎?阿里面試題索引
- MySQL null值欄位是否使用索引的總結MySqlNull索引
- DataFrame刪除複合索引索引
- 12.索引合併-indexMerge索引Index
- MongoDB複合索引詳解MongoDB索引
- 淺談聚簇索引與非聚簇索引索引