oracle index range scan,深入理解Oracle索引(1):INDEX SKIP SCAN 和 INDEX RANGE SCAN | 學步園...
㈠ Index SKIP SCAN當表有一個複合索引,而在查詢中有除了索引中第一列的其他列作為條件,並且優化器模式為CBO,這時候查詢計劃就有可能使用到SS
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的條目。最後合併兩個結果集
ORACLE官方說,在前導列唯一值較少的情況下,才會用到index skip can。這個其實好理解,就是入口要少,這也是skip scan的條件
ORACLE也承認skip scan沒有直接索引查詢快,但可以這樣說,相比於整個表掃描(table scan),索引跳躍式掃描的速度要快得多
在Oracle9i版本之前,當SQL查詢中包含sex和employee_id時,或者查詢指定sex的時候才可以使用這一索引,下面的查詢就不能使用索引:
select employee_id from employees where employee_id=7788;
Oracle9i的索引跳躍式掃描執行規則允許使用連接索引,即使SQL查詢中不指定性別
這一特性使得無需在employee_id行中提供第二個索引
索引跳躍式掃描適用於硬盤空間和存儲空間相當緊缺的情況
因為一個索引可以滿足兩個查詢條件的使用,比單獨建兩個索引自然節約了空間
例如:
hr@ORCL> desc t
Name Null? Type
----------------------------------------------------- -------- ------------------------------------
EMPNO NOT NULL NUMBER
SEX NOT NULL VARCHAR2(4)
ENAME VARCHAR2(4)
hr@ORCL> create index sex_empno on t (sex,empno);
Index created.
hr@ORCL> analyze index sex_empno compute statistics;
Index analyzed.
hr@ORCL> select /*+ index_ss(t) */ empno from t where empno=8;
Execution Plan
----------------------------------------------------------
Plan hash value: 3008009344
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 3 (0)| 00:00:01 |
|* 1 | INDEX SKIP SCAN | SEX_EMPNO | 1 | 10 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------
先看個圖:

假如我現在要查找employee_id是109的記錄,從圖可以看出來,109的記錄存在與塊3和塊5上
但是skip scan是通過什麼樣的方式定位到這兩個塊呢?
ORACLE可以在SKIP SCAN中,選擇相應的入口後,通過根節點和分支節點的信息,非常精準的定位到記錄的葉子塊,即塊3和塊5.
如果要查找employee_id為109的條目,ORACLE進入到入口M後,直接就可以定位到塊3.而不需要掃描塊1和塊2.
進入到入口F後,直接就可以定位到塊5,而不需要掃描塊4和塊6
那麼,我們上面這條查詢,經過skip scan後,內部可能是:
select empno from t where sex='M' and empno=8
union
select empno from t where sex='F' and empno=8;
我們可以想象,如果索引前導列的唯一值很多,那麼勢必會大大削弱skip scan的效能,因為可能存在很多union
有時候為了避免index skip scan,建立新的索引是有必要的
㈡ INDEX Range Scan
INDEX Range SCAN是一種很常見的表訪問方式
在INDEX Range SCAN中,Oracle訪問毗鄰的索引條目,然後根據索引裡面的rowid去檢索表的記錄
例如:查詢範圍為80號部門裡的所有員工
hr@ORCL> select JOB_ID,FIRST_NAME from employees where DEPARTMENT_ID=80;
Execution Plan
----------------------------------------------------------
Plan hash value: 2056577954
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 34 | 646 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 34 | 646 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 34 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------
INDEX RANGE SCAN是範圍掃描,舉個例子,有1到100,分5個範圍,要查詢45就要到第3的範圍里查,這樣會很快
Index Unique Scan和Index Range Scan在B Tree上的搜索路徑是一樣的
只是Index Unique Scan在找到應該含有要找的Index Key的block後便停止了搜索,因為該鍵是唯一的
而Index Range Scan還要循着指針繼續找下去直到條件不滿足時
並且,Index Range Scan只是索引上的查詢,與是否掃描表沒有關係
如果所選擇的列都在index上就不用去scan table
如果掃描到表, 必然還有一個table access by rowid,正如上例所展示的
通過index range scan訪問的表可以通過按照索引順序重新建立表來提高效率
原因有二:
① 如果你只讀一部分數據,假設20% ,如果表數據順序混亂,實際上可能把整個表都讀進來了
如果表順序和索引一致,則只需要讀進 20%的表的block就夠了。這是簡單情況
② 複雜情況下,順序混亂的時候 block 可能在整個查詢的不同時間點多次反覆訪問
當再次要訪問這個塊的時候說不定已經被換出去了,或者被修改過了,那代價更大
而如果順序一樣,對同一個block的訪問集中在一段連續的很短的時間內,變數少,不會對同一個block產生多次IO
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)