索引

索引掃描(Index scan)

  我們先通過index查找到數據對應的rowid值(對於非唯一索引可能返回多個rowid值),然後根據rowid直接從表中得到具體的數據,這種查找方式稱爲索引掃描或索引查找(index lookup)。一個rowid唯一的表示一行數據,該行對應的數據塊是通過一次i/o得到的,在此情況下該次i/o只會讀取一個數據庫塊。在索引中,除了存儲每個索引的值外,索引還存儲具有此值的行對應的ROWID值。索引掃描可以由2步組成: (1) 掃描索引得到對應的rowid值。 (2) 通過找到的rowid從表中讀出具體的數據。

 根據索引的類型與where限制條件的不同,有5種類型的索引掃描:

1)索引唯一掃描(index unique scan)

2)索引範圍掃描(index range scan)

3)索引全掃描(index full scan)

4)索引快速掃描(index fast full scan)

5)索引跳躍掃描(INDEX SKIP SCAN)

索引唯一掃描(INDEX UNIQUE SCAN)

  通過唯一索引查找一個數值經常返回單個ROWID

唯一索引由單獨列組成:

複製代碼

 1 --收集統計信息
 2 SQL> exec dbms_stats.gather_table_stats('SCOTT','EMP');
 3 
 4 PL/SQL procedure successfully completed.
 5 
 6 Commit complete.
 7 SQL> 
 8 
 9 
10 --獲取創建索引語句
11 SQL> SELECT DBMS_METADATA.GET_DDL('INDEX',u.index_name)
12   2  FROM USER_INDEXES u
13   3  WHERE u.TABLE_NAME='EMP';
14 
15 DBMS_METADATA.GET_DDL('INDEX',U.INDEX_NAME)
16 --------------------------------------------------------------------------------
17   CREATE UNIQUE INDEX "SCOTT"."PK_EMP" ON "SCOTT"."EMP" ("EMPNO")
18   PCTFREE 10
19 
20 SQL>
21 
22     1.索引名稱 PK_EMP
23     2.索引包含列 EMPNO
24     3.索引爲唯一索引
25 
26     --執行計劃走唯一索引的語句
27     SQL> SELECT * FROM SCOTT.EMP WHERE EMPNO='7369';
28     
29     Execution Plan
30     ----------------------------------------------------------
31     Plan hash value: 2949544139
32     
33     --------------------------------------------------------------------------------------
34     | Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
35     --------------------------------------------------------------------------------------
36     |   0 | SELECT STATEMENT            |        |     1 |    38 |     1   (0)| 00:00:01 |
37     |   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |     1 |    38 |     1   (0)| 00:00:01 |
38     |*  2 |   INDEX UNIQUE SCAN         | PK_EMP |     1 |       |     0   (0)| 00:00:01 |
39     --------------------------------------------------------------------------------------
40     
41     Predicate Information (identified by operation id):
42     ---------------------------------------------------
43     
44        2 - access("EMPNO"=7369)
45        
46        
47     
48     SQL> SELECT * FROM SCOTT.EMP WHERE EMPNO IN ('7499','7521');
49     
50     
51     Execution Plan
52     ----------------------------------------------------------
53     Plan hash value: 2355049923
54     
55     ---------------------------------------------------------------------------------------
56     | Id  | Operation                    | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
57     ---------------------------------------------------------------------------------------
58     |   0 | SELECT STATEMENT             |        |     2 |    76 |     2   (0)| 00:00:01 |
59     |   1 |  INLIST ITERATOR             |        |       |       |            |          |
60     |   2 |   TABLE ACCESS BY INDEX ROWID| EMP    |     2 |    76 |     2   (0)| 00:00:01 |
61     |*  3 |    INDEX UNIQUE SCAN         | PK_EMP |     2 |       |     1   (0)| 00:00:01 |
62     ---------------------------------------------------------------------------------------
63     
64     Predicate Information (identified by operation id):
65     ---------------------------------------------------
66     
67        3 - access("EMPNO"=7499 OR "EMPNO"=7521)
68     
69     SQL> SELECT * FROM SCOTT.EMP WHERE EMPNO='7499' OR EMPNO='7521';
70     
71     Execution Plan
72     ----------------------------------------------------------
73     Plan hash value: 2355049923
74     
75     ---------------------------------------------------------------------------------------
76     | Id  | Operation                    | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
77     ---------------------------------------------------------------------------------------
78     |   0 | SELECT STATEMENT             |        |     2 |    76 |     2   (0)| 00:00:01 |
79     |   1 |  INLIST ITERATOR             |        |       |       |            |          |
80     |   2 |   TABLE ACCESS BY INDEX ROWID| EMP    |     2 |    76 |     2   (0)| 00:00:01 |
81     |*  3 |    INDEX UNIQUE SCAN         | PK_EMP |     2 |       |     1   (0)| 00:00:01 |
82     ---------------------------------------------------------------------------------------
83     
84     Predicate Information (identified by operation id):
85     ---------------------------------------------------
86     
87        3 - access("EMPNO"=7499 OR "EMPNO"=7521)
88     SQL>

複製代碼

 SELECT * FROM SCOTT.EMP WHERE EMPNO='7369';
 SELECT * FROM SCOTT.EMP WHERE EMPNO IN ('7499','7521');
 SELECT * FROM SCOTT.EMP WHERE EMPNO='7499' OR EMPNO='7521'
 總結,索引在where條件中,且謂詞條件可以確定唯一值時,走唯一索引。思考下2,3語句的查詢過程

 

唯一索引由多個列組成(即組合索引)

複製代碼

 1     --創建一個唯一索引(優質索引)
 2     create unique index scott.idx_test on scott.emp(ename, deptno); --ename爲引導列,表中ename列值具有唯一性
 3 
 4   --謂詞條件中的列順序與索引的列順序完全一致,走唯一索引
 5     SQL> select * from scott.emp where  ename = 'ALLEN' and deptno = 20 ;
 6     
 7     no rows selected
 8     
 9     
10     Execution Plan
11     ----------------------------------------------------------
12     Plan hash value: 4010583877
13     
14     ----------------------------------------------------------------------------------------
15     | Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
16     ----------------------------------------------------------------------------------------
17     |   0 | SELECT STATEMENT            |          |     1 |    38 |     1   (0)| 00:00:01 |
18     |   1 |  TABLE ACCESS BY INDEX ROWID| EMP      |     1 |    38 |     1   (0)| 00:00:01 |
19     |*  2 |   INDEX UNIQUE SCAN         | IDX_TEST |     1 |       |     0   (0)| 00:00:01 |
20     ----------------------------------------------------------------------------------------
21     
22     Predicate Information (identified by operation id):
23     ---------------------------------------------------
24     
25        2 - access("ENAME"='ALLEN' AND "DEPTNO"=20)
26     
27     
28   --謂詞條件中的列順序與唯索引的列順序不一致    ,走唯一索引
29     SQL> select * from scott.emp where deptno = 20 and ename = 'ALLEN'; 
30     
31     no rows selected
32     
33     
34     Execution Plan
35     ----------------------------------------------------------
36     Plan hash value: 4010583877
37     
38     ----------------------------------------------------------------------------------------
39     | Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
40     ----------------------------------------------------------------------------------------
41     |   0 | SELECT STATEMENT            |          |     1 |    38 |     1   (0)| 00:00:01 |
42     |   1 |  TABLE ACCESS BY INDEX ROWID| EMP      |     1 |    38 |     1   (0)| 00:00:01 |
43     |*  2 |   INDEX UNIQUE SCAN         | IDX_TEST |     1 |       |     0   (0)| 00:00:01 |
44     ----------------------------------------------------------------------------------------
45     
46     Predicate Information (identified by operation id):
47     ---------------------------------------------------
48     
49        2 - access("ENAME"='ALLEN' AND "DEPTNO"=20)
50     
51     --只有引導列在謂詞條件中
52     SQL> select * from scott.emp where ename = 'ALLEN'; --即使是唯一數據 也不走唯一索引
53     
54     
55     Execution Plan
56     ----------------------------------------------------------
57     Plan hash value: 2317538385
58     
59     ----------------------------------------------------------------------------------------
60     | Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
61     ----------------------------------------------------------------------------------------
62     |   0 | SELECT STATEMENT            |          |     1 |    38 |     2   (0)| 00:00:01 |
63     |   1 |  TABLE ACCESS BY INDEX ROWID| EMP      |     1 |    38 |     2   (0)| 00:00:01 |
64     |*  2 |   INDEX RANGE SCAN          | IDX_TEST |     1 |       |     1   (0)| 00:00:01 |
65     ----------------------------------------------------------------------------------------
66     
67     Predicate Information (identified by operation id):
68     ---------------------------------------------------
69     
70        2 - access("ENAME"='ALLEN')
71 
72 
73     --引導列不在謂詞條件中
74     SQL> select * from scott.emp where deptno = 20;
75     
76     
77     Execution Plan
78     ----------------------------------------------------------
79     Plan hash value: 3956160932
80     
81     --------------------------------------------------------------------------
82     | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
83     --------------------------------------------------------------------------
84     |   0 | SELECT STATEMENT  |      |     5 |   190 |     3   (0)| 00:00:01 |
85     |*  1 |  TABLE ACCESS FULL| EMP  |     5 |   190 |     3   (0)| 00:00:01 |
86     --------------------------------------------------------------------------
87     
88     Predicate Information (identified by operation id):
89     ---------------------------------------------------
90     
91        1 - filter("DEPTNO"=20)
92     
93     SQL>     

複製代碼

 

複製代碼

 1     --創建一個唯一索引(劣質索引)
 2     create unique index idx_test on scott.emp(deptno,ename); --deptno爲引導列,表中deptno列值不具有唯一性
 3     
 4     分別對別如下sql的執行計劃:
 5     --謂詞條件中的列順序與索引的列順序完全一致,,走唯一索引
 6     SQL> select * from scott.emp where deptno = 20 and ename = 'ALLEN'; 
 7     
 8     no rows selected
 9         
10     Execution Plan
11     ----------------------------------------------------------
12     Plan hash value: 1531058326
13     
14     ------------------------------------------------------------------------------------------
15     | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
16     ------------------------------------------------------------------------------------------
17     |   0 | SELECT STATEMENT            |            |     1 |    38 |     1   (0)| 00:00:01 |
18     |   1 |  TABLE ACCESS BY INDEX ROWID| EMP        |     1 |    38 |     1   (0)| 00:00:01 |
19     |*  2 |   INDEX UNIQUE SCAN         | IDX_TEST01 |     1 |       |     0   (0)| 00:00:01 |
20     ------------------------------------------------------------------------------------------
21     
22     Predicate Information (identified by operation id):
23     ---------------------------------------------------
24     
25        2 - access("DEPTNO"=20 AND "ENAME"='ALLEN')
26     
27     SQL>    
28     
29   --謂詞條件中的列順序與唯索引的列順序不一致    ,走唯一索引
30     SQL> select * from scott.emp where  ename = 'ALLEN' and deptno = 20 ;
31     
32     no rows selected
33     
34     Execution Plan
35     ----------------------------------------------------------
36     Plan hash value: 1531058326
37     
38     ------------------------------------------------------------------------------------------
39     | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
40     ------------------------------------------------------------------------------------------
41     |   0 | SELECT STATEMENT            |            |     1 |    38 |     1   (0)| 00:00:01 |
42     |   1 |  TABLE ACCESS BY INDEX ROWID| EMP        |     1 |    38 |     1   (0)| 00:00:01 |
43     |*  2 |   INDEX UNIQUE SCAN         | IDX_TEST01 |     1 |       |     0   (0)| 00:00:01 |
44     ------------------------------------------------------------------------------------------
45     
46     Predicate Information (identified by operation id):
47     ---------------------------------------------------
48     
49        2 - access("DEPTNO"=20 AND "ENAME"='ALLEN')
50     
51     SQL>     
52     
53     --只有引導列在謂詞條件中
54     SQL> select * from scott.emp where deptno = 20;
55         
56     Execution Plan
57     ----------------------------------------------------------
58     Plan hash value: 560737562
59     
60     ------------------------------------------------------------------------------------------
61     | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
62     ------------------------------------------------------------------------------------------
63     |   0 | SELECT STATEMENT            |            |     5 |   190 |     2   (0)| 00:00:01 |
64     |   1 |  TABLE ACCESS BY INDEX ROWID| EMP        |     5 |   190 |     2   (0)| 00:00:01 |
65     |*  2 |   INDEX RANGE SCAN          | IDX_TEST01 |     5 |       |     1   (0)| 00:00:01 |
66     ------------------------------------------------------------------------------------------
67     
68     Predicate Information (identified by operation id):
69     ---------------------------------------------------
70     
71        2 - access("DEPTNO"=20)
72     SQL>    
73     
74     --引導列不在謂詞條件
75     SQL> select * from scott.emp where ename = 'ALLEN';
76     
77     Execution Plan
78     ----------------------------------------------------------
79     Plan hash value: 3956160932
80     
81     --------------------------------------------------------------------------
82     | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
83     --------------------------------------------------------------------------
84     |   0 | SELECT STATEMENT  |      |     1 |    38 |     3   (0)| 00:00:01 |
85     |*  1 |  TABLE ACCESS FULL| EMP  |     1 |    38 |     3   (0)| 00:00:01 |
86     --------------------------------------------------------------------------
87     
88     Predicate Information (identified by operation id):
89     ---------------------------------------------------
90     
91        1 - filter("ENAME"='ALLEN')
92     
93     SQL>     

複製代碼

 總結:使用組合索引時,遵守以下原則:

1.引導列標識性要強;

2.索引列儘量全部出現在謂詞條件中

3.引導列儘量出現在謂詞條件中

索引範圍掃描(INDEX RANGE SCAN)

  使用一個索引存取多行數據,在唯一索引上使用索引範圍掃描的典型情況下是在謂詞(where限制條件)中使用了範圍操作符 (如>、<、<>、>=、<=、between)。在非唯一索引上,謂詞"="也可能返回多行數據,所以在非唯一索引上都使用索引範圍掃描。

  使用index rang scan的3種情況:  

  1.在唯一索引列上使用了range操作符(> < <> >= <= between)  

  2.在組合索引上,只使用部分列進行查詢,導致查詢出多行  

  3.對非唯一索引列上進行的任何查詢。

  通過index range scan訪問的表可以通過按照索引順序重新建立表來提高效率:

複製代碼

1.如果你只讀一部分數據,假設20% ,如果表數據順序混亂,實際上可能把整個表都讀進來了;
  如果表順序和索引一致,則只需要讀進 20%的表的block就夠了。這是簡單情況
2.複雜情況下,順序混亂的時候 block  可能在整個查詢的不同時間點多次反覆訪問
  當再次要訪問這個塊的時候說不定已經被換出去了,或者被修改過了,那代價更大
  而如果順序一樣,對同一個block的訪問集中在一段連續的很短的時間內,變數少,不會對同一個block產生多次IO

複製代碼

Index Unique Scan對比Index Range Scan

複製代碼

1.Index Unique Scan和Index Range Scan在B Tree上的搜索路徑是一樣的
2.Index Unique Scan在找到應該含有要找的Index Key的block後便停止了搜索,因爲該鍵是唯一的;而Index Range Scan還要循着指針繼續找下去直到條件不滿足時 
3.Index Unique Scan和Index Range Scan都只是索引上的查詢,與是否掃描表沒有關係。
  如果所選擇的列都在index上就不用去scan table;如果掃描到表, 必然還有一個table access by rowid

複製代碼

 

索引全掃描(index full scan)

  與全表掃描對應,也有相應的全索引掃描。在某些情況下,可能進行全索引掃描而不是範圍掃描,需要注意的是全索引掃描只在CBO模式下才有效。 CBO根據統計數值得知進行全索引掃描比進行全表掃描更有效時,才進行全索引掃描,而且此時查詢出的數據都必須從索引中可以直接得到。
 
  一般通過索引進行排序時,會用到(index full scan)

索引快速掃描(index fast full scan)

  掃描索引中的所有的數據塊,與 index full scan很類似,但是一個顯著的區別就是它不對查詢出的數據進行排序,即數據不是以排序順序被返回。在這種存取方法中,可以使用多塊讀功能,也可以使用並行讀入,以便獲得最大吞吐量與縮短執行時間。

索引跳躍掃描(INDEX SKIP SCAN)

  Skip Scans are initiated by probing the index for distinct values of the prefix column. Each of these distinct values is then used as a starting point for a regular index search. The result is several separate searches of a single index that, when combined, eliminate the affect of the prefix column.

  skip scan會探測出索引前導列的唯一值個數,每個唯一值都會作爲常規掃描的入口,在此基礎上做一次查找,最後合併 這些查詢。例如:表employees (sex, employee_id, address) ,有一個組合索引(sex, employee_id). 在索引跳躍的情況 下,我們可以邏輯上把他們看成兩個索引,一個是(男,employee_id),一個是(女,employee_id). select * from employees where employee_id=1;發出這個查詢後,oracle先進入sex爲男的入口,查找employee_id=1的條目。 再進入sex爲女的入口,查找employee_id=1的條目。最後合併兩個結果集

 

參考blog:http://www.itpub.net/thread-1372696-1-1.html

     http://blog.csdn.net/dba_waterbin/article/details/8550405

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章