組合索引的前導列與查詢——ORACLE
關於組合索引的使用一直都存在著一些爭議,記得在學OU的Performance Tuning時,講師認為組合索引的使用存在著一定的侷限,只有在謂詞中出現全部索引列時才能使用效率最高的index unique scan, 否則謂詞中必須包含前導列,否則會走Index full scan或者FTS。
kl@k02> create table te_emp as select * from hr.employees;
Table created.
kl@k02> create index emp_id1 on te_emp(employee_id,JOB_ID, department_id);
Index created.
kl@k02> create index emp_id2 on te_emp(salary);
Index created.
kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes;
Table analyzed.
kl@k02> set autotrace traceonly exp;
kl@k02> select employee_id,JOB_ID, department_id from te_emp;
(不加謂詞,走EMP_ID1的FULL SCAN)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=107 Bytes=1391)
1 0 INDEX (FULL SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=107 Bytes=1391)
kl@k02> select employee_id,JOB_ID, department_id from te_emp where employee_id=9293;
(加謂詞前導列Employee_id時,走EMP_ID1 range scan)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=13)
1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=1 Bytes=13)
kl@k02> select employee_id,JOB_ID, department_id from te_emp where employee_id=1334 and JOB_ID=435 and department_id=273;
(如謂詞中包含全部索引列,走EMP_ID1 Range scan)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=13)
1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1 Bytes=13)
kl@k02> set autotrace off;
kl@k02> select count(*) from (select distinct employee_id from te_emp);
COUNT(*)
----------
107
kl@k02> select count(*) from te_emp;
COUNT(*)
----------
107
kl@k02> create index emp_id3 on te_emp(employee_id);
(此時建立一個單列索引emp_id3, 目前組合索引emp_id1仍然存在)
Index created.
kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes;
Table analyzed.
kl@k02> select employee_id from te_emp where employee_id=107;
(並沒有走emp_id3, 而是emp_id1的INDEX RANGE SCAN)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=3)
1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1 Bytes=3)
kl@k02> drop index emp_id1;
Index dropped.
kl@k02> select employee_id from te_emp where employee_id=107;
(drop原來的聯合索引,用到了emp_id3,但是還是INDEX RANGE SCAN)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=3)
1 0 INDEX (RANGE SCAN) OF 'EMP_ID3' (NON-UNIQUE) (Cost=1 Card=1 Bytes=3)
(現在測試一下,如果組合index是unique index,會如何?)
kl@k02> drop index emp_id3;
Index dropped.
kl@k02> create unique index emp_id1 on te_emp(employee_id,JOB_ID, department_id);
Index created.
kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes;
Table analyzed.
kl@k02> select * from te_emp where employee_id=107 and JOB_ID='ENGINEER' and department_id=10;
(此時走了unique scan,也就是說只有這種情況聯合索引的作用才發揮出來)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=62)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=1 Card=1 Bytes=62)
2 1 INDEX (UNIQUE SCAN) OF 'EMP_ID1' (UNIQUE)
kl@k02> select * from te_emp where employee_id=107;
(此時謂詞內只有前導列,不會走unique scan)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=1 Bytes=62)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=2 Card=1 Bytes=62)
2 1 INDEX (RANGE SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=1)
kl@k02> select * from te_emp where employee_id=107 and JOB_ID=999 and department_id=10;
(JOB_ID應該是Varchar型的,結果導致整個查詢無法走Unique scan)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=1 Bytes=62)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=2 Card=1 Bytes=62)
2 1 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1)
kl@k02> select * from te_emp where employee_id='TEST' and JOB_ID='TEST' and department_id=10;
(如果前導列型別出錯了,索引掃描型別還是一樣,UNIQUE SCAN)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=62)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=1 Card=1 Bytes=62)
2 1 INDEX (UNIQUE SCAN) OF 'EMP_ID1' (UNIQUE)
總結,針對組合索引,比較適宜的情況是組合列唯一,這種情況下對組合列建組合UNIQUE索引受益最大,一次索引掃描就可以了。但如果其中非前導列型別出錯,索引UNIQUE掃描將變成RANGE SCAN; 有趣的是如果前導列型別不對,甚至為null,都不影響組合索引的UNIQUE SCAN.
kl@k02> create table te_emp as select * from hr.employees;
Table created.
kl@k02> create index emp_id1 on te_emp(employee_id,JOB_ID, department_id);
Index created.
kl@k02> create index emp_id2 on te_emp(salary);
Index created.
kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes;
Table analyzed.
kl@k02> set autotrace traceonly exp;
kl@k02> select employee_id,JOB_ID, department_id from te_emp;
(不加謂詞,走EMP_ID1的FULL SCAN)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=107 Bytes=1391)
1 0 INDEX (FULL SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=107 Bytes=1391)
kl@k02> select employee_id,JOB_ID, department_id from te_emp where employee_id=9293;
(加謂詞前導列Employee_id時,走EMP_ID1 range scan)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=13)
1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=1 Bytes=13)
kl@k02> select employee_id,JOB_ID, department_id from te_emp where employee_id=1334 and JOB_ID=435 and department_id=273;
(如謂詞中包含全部索引列,走EMP_ID1 Range scan)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=13)
1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1 Bytes=13)
kl@k02> set autotrace off;
kl@k02> select count(*) from (select distinct employee_id from te_emp);
COUNT(*)
----------
107
kl@k02> select count(*) from te_emp;
COUNT(*)
----------
107
kl@k02> create index emp_id3 on te_emp(employee_id);
(此時建立一個單列索引emp_id3, 目前組合索引emp_id1仍然存在)
Index created.
kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes;
Table analyzed.
kl@k02> select employee_id from te_emp where employee_id=107;
(並沒有走emp_id3, 而是emp_id1的INDEX RANGE SCAN)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=3)
1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1 Bytes=3)
kl@k02> drop index emp_id1;
Index dropped.
kl@k02> select employee_id from te_emp where employee_id=107;
(drop原來的聯合索引,用到了emp_id3,但是還是INDEX RANGE SCAN)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=3)
1 0 INDEX (RANGE SCAN) OF 'EMP_ID3' (NON-UNIQUE) (Cost=1 Card=1 Bytes=3)
(現在測試一下,如果組合index是unique index,會如何?)
kl@k02> drop index emp_id3;
Index dropped.
kl@k02> create unique index emp_id1 on te_emp(employee_id,JOB_ID, department_id);
Index created.
kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes;
Table analyzed.
kl@k02> select * from te_emp where employee_id=107 and JOB_ID='ENGINEER' and department_id=10;
(此時走了unique scan,也就是說只有這種情況聯合索引的作用才發揮出來)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=62)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=1 Card=1 Bytes=62)
2 1 INDEX (UNIQUE SCAN) OF 'EMP_ID1' (UNIQUE)
kl@k02> select * from te_emp where employee_id=107;
(此時謂詞內只有前導列,不會走unique scan)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=1 Bytes=62)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=2 Card=1 Bytes=62)
2 1 INDEX (RANGE SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=1)
kl@k02> select * from te_emp where employee_id=107 and JOB_ID=999 and department_id=10;
(JOB_ID應該是Varchar型的,結果導致整個查詢無法走Unique scan)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=1 Bytes=62)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=2 Card=1 Bytes=62)
2 1 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1)
kl@k02> select * from te_emp where employee_id='TEST' and JOB_ID='TEST' and department_id=10;
(如果前導列型別出錯了,索引掃描型別還是一樣,UNIQUE SCAN)
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=1 Card=1 Bytes=62)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=1 Card=1 Bytes=62)
2 1 INDEX (UNIQUE SCAN) OF 'EMP_ID1' (UNIQUE)
總結,針對組合索引,比較適宜的情況是組合列唯一,這種情況下對組合列建組合UNIQUE索引受益最大,一次索引掃描就可以了。但如果其中非前導列型別出錯,索引UNIQUE掃描將變成RANGE SCAN; 有趣的是如果前導列型別不對,甚至為null,都不影響組合索引的UNIQUE SCAN.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/751371/viewspace-567130/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 複合索引中前導列對sql查詢的影響索引SQL
- 【oracle 效能優化】組合索引查詢。Oracle優化索引
- 聊聊mysql的多列組合查詢MySql
- 使用組合索引處理包含空值的查詢索引
- 【索引】Oracle查詢指定索引提高查詢效率索引Oracle
- 組合查詢 (轉)
- 組合查詢(UNION)
- mysql-分組查詢-子查詢-連線查詢-組合查詢MySql
- 索引與null(二):組合索引索引Null
- MySQL單列索引和組合索引的區別MySql索引
- oracle查詢表資訊(索引,外來鍵,列等)Oracle索引
- ORACLE 組合索引 使用分析Oracle索引
- 關於聯合索引,範圍查詢,時間列索引的幾個問題索引
- [MYSQL -17]組合查詢MySql
- MySQL單列索引和組合索引的區別介紹MySql索引
- Oracle中組合索引的使用詳解Oracle索引
- MongoDB慢查詢與索引MongoDB索引
- 反向索引與模糊查詢索引
- 【索引】oracle查詢使用索引和不使用索引的比較索引Oracle
- MySQL全面瓦解11:子查詢和組合查詢MySql
- mysql的組合索引MySql索引
- SQL 兩個表組合查詢SQL
- Oracle如何查詢當前LockOracle
- MySQL索引與查詢優化MySql索引優化
- MySQL 合併查詢join 查詢出的不同列合併到一個表中MySql
- 什麼是index的leading column(索引的前導列)?Index索引
- MySQL入門系列:查詢簡介(七)之組合查詢MySql
- 17. 使用MySQL之組合查詢MySql
- jpa動態查詢與多表聯合查詢
- 帶有儲存過程的組合查詢儲存過程
- 阿里面試題: (a,b,c)組合索引, 查詢語句select...from...where a=.. and c=..走索引嗎?阿里面試題索引
- 查詢前10條資料oracleOracle
- Oracle分組查詢中包含子查詢列,發生ORA-00937:不是單分組函式的錯誤Oracle函式
- 水煮oracle31----連線查詢&合併查詢Oracle
- Oracle查詢當前會話的sidOracle會話
- mysql組合索引,abc索引命中MySql索引
- 繫結變數,組合查詢方式,導致CBO錯誤一例變數
- oracle組合索引什麼情況下生效?Oracle索引