㈠ 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 |

------------------------------------------------------------------------------

先看個圖:

1359381046_6371.png

假如我現在要查找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

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐