Oracle還是比較常用的,於是我研究了一下Oracle索引掃描,在這裡拿出來和大家分享一下,希望對大家有用。我們先通過index查找到數據對應的rowid值(對於非唯一索引可能返回多個rowid值),然後根據rowid直接從表中得到具體的數據,這種查找方式稱為Oracle索引掃描或索引查找(index lookup)。一個rowid唯一的表示一行數據,該行對應的數據塊是通過一次i/o得到的,在此情況下該次i/o只會讀取一個數據庫塊。
在索引中,除了存儲每個索引的值外,索引還存儲具有此值的行對應的ROWID值。Oracle索引掃描可以由2步組成:
(1) 掃描索引得到對應的rowid值。
(2) 通過找到的rowid從表中讀出具體的數據。
每步都是單獨的一次I/O,但是對於索引,由於經常使用,絕大多數都已經CACHE到內存中,所以第1步的I /O經常是邏輯I/O,即數據可以從內存中得到。但是對於第2步來說,如果表比較大,則其數據不可能全在內存中,所以其I/O很有可能是物理I/O,這是一個機械操作,相對邏輯I/O來說,是極其費時間的。所以如果多大表進行索引掃描,取出的數據如果大於總量的5% -- 10%,使用索引掃描會效率下降很多。
如下列所示:
- SQL> explain plan for select empno, ename from emp where empno=10;
- Query Plan
- SELECT STATEMENT [CHOOSE] Cost=1
- TABLE Access BY ROWID EMP [ANALYZED]
- INDEX UNIQUE SCAN EMP_I1
注意TABLE Access BY ROWID EMP部分,這表明這不是通過FTS存取路徑訪問數據,而是通過rowid lookup存取路徑訪問數據的。在此例中,所需要的rowid是由於在索引查找empno列的值得到的,這種方式是INDEX UNIQUE SCAN查找,後面給予介紹,EMP_I1為使用的進行索引查找的索引名字。
但是如果查詢的數據能全在索引中找到,就可以避免進行第2步操作,避免了不必要的I/O,此時即使通過Oracle索引掃描取出的數據比較多,效率還是很高的,因為這只會在索引中讀取。所以上面我在介紹基於規則的優化器時,使用了select count(id) from SWD_BILLDETAIL where cn <'6',而沒有使用select count(cn) from SWD_BILLDETAIL where cn <'6'。因為在實際情況中,只查詢被索引列的值的情況極為少,所以,如果我在查詢中使用count(cn),則不具有代表性。
- SQL> explain plan for select empno from emp where empno=10; -- 只查詢empno列值
- Query Plan
- SELECT STATEMENT [CHOOSE] Cost=1
- INDEX UNIQUE SCAN EMP_I1
進一步講,如果sql語句中對索引列進行排序,因為索引已經預先排序好了,所以在執行計劃中不需要再對索引列進行排序
- SQL> explain plan for select empno, ename from emp
- where empno > 7876 order by empno;
- Query Plan
- SELECT STATEMENT [CHOOSE] Cost=1
- TABLE Access BY ROWID EMP [ANALYZED]
- INDEX RANGE SCAN EMP_I1 [ANALYZED]
從這個例子中可以看到:因為索引是已經排序了的,所以將按照索引的順序查詢出符合條件的行,因此避免了進一步排序操作。