1. 程式人生 > 實用技巧 >一文講透如何看懂Oracle索引執行型別(index unique scan,index range scan,index full scan,index fast full scan,index skip scan)

一文講透如何看懂Oracle索引執行型別(index unique scan,index range scan,index full scan,index fast full scan,index skip scan)

直入主題,因為看不懂Oracle的執行計劃/解釋計劃(explain plan),我摸著石頭過河,終於整理出一點關於oracle各種索引執行型別的小心得,希望能幫到面向百度程式設計各位!

index unique scan -- 索引唯一掃描

條件:

1. 列的值唯一

2. 用 '=' 來查詢

index range scan -- 索引區域性掃描

條件:

1. 列的值唯一

2. 範圍查詢(>, <, and...)

or

1. 列的值不唯一

2. 所有查詢(=, >, <, and...)

index full scan -- 索引全域性掃描

條件:

1. 必須是組合索引

2. 引導列不在where條件中

PS: 當進行index full scan的時候 oracle定位到索引的root block,然後到branch block(如果有的話),再定位到第一個leaf block, 然後根據leaf block的雙向連結串列順序讀取。它所讀取的塊都是有順序的,也是經過排序的。

index fast full scan -- 索引快速全域性掃描,不帶order by 情況下常發生

如果select 語句後面中的列都被包含在組合索引中,而且where後面沒有出現組合索引的引導列,並且需要檢索出大部分資料,那麼這個時候可能執行index fast full scan

條件:

1. 必須是組合索引

2. 引導列不在where條件中

PS:index fast full scan則不同,它是從段頭開始,讀取包含點陣圖塊,root block, 所有的branch block, leaf block,讀取的順序完全由物理儲存位置決定,並採取多塊讀,每次讀取db_file_multiblock_read_count個。

所以:
1. 索引全掃描要排序,索引快速全掃描不用排序(索引全掃描會按照葉子塊排序返回,而索引快速全掃描則是按照索引段記憶體儲塊順序返回)。
2. 索引全掃描不得讀取索引段頭,而索引快速全掃描要讀取索引段頭

index skip scan -- 索引跳躍掃描,where 條件列是非索引的前導列情況下常發生

當查詢可以通過組合索引得到結果,而且返回結果很少,並且where條件中沒有包含索引引導列的時候,可能執行index skip scan

條件:

1. 必須是組合索引

2. 引導列不在where條件中

by index Rowid 列名 --Rowid 掃描是最快的訪問資料方式

用主鍵查詢或者回表查詢時會出現

下列是我遇到的問題:

原SQL:

select accountid, validRecord from bi_TINbatchimportrecord 
where batchid = 'HK#ACCOUNT-BATCH#20190501#96732a40-aebe-4354-b83d-3c6f781c6df1'
group by accountid, validrecord ;

原索引:

INDEX1 (BATCHID, ACCOUNTID, IMPORTTYPE, BUSINESSKEY)


INDEX2(ACCOUNTID, BATCHID, VALIDRECORD, VALIDBATCHID)

問題 : 以為會用INDEX1,但用的是INDEX2

=================== 目前 INDEX2 ===================


用到INDEX2作為索引,以INDEX FAST FULL SCAN/INDEX SKIP SCAN的方式(where沒有引導列,且索引是覆蓋索引,根據索引具體COST來決定用哪種方式)

-- INDEX FAST FULL SCAN:
INDEX2索引樹全樹無序掃描,採取多塊讀的方式

-- INDEX SKIP SCAN:

select accountid, validRecord from bi_TINbatchimportrecord
where batchid = 'batchid'
----- Oracle優化 ----->
select accountid, validRecord from bi_TINbatchimportrecord
where accountid = 'acctid1' and batchid = 'batchid'
union
select accountid, validRecord from bi_TINbatchimportrecord
where accountid = 'acctid2' and batchid = 'batchid'
union
......

所以,accountid越集中,union次數越少,效率越高

=================== 強制 INDEX1 ===================

** 根據我當時淺薄的認知,複合索引應該依照最左原則,哪個複合索引的引導項是batchid,就應該用哪個


若強制使用INDEX1,用到BATCHID作為索引,先以RANGE SCAN的方式查到(ID, BATCHID, ACCOUNTID, IMPORTTYPE, BUSINESSKEY),找不到需要的validRecord,
再進行回表查詢,效率取決於回表查的資料量

所以,索引不是覆蓋索引的前提下,通過查出來 BATCHID='xxx' 的記錄數越多,需要回表查詢的記錄越多,資料庫是按大小分成資料片的,每次IO取一片,意味著回表記錄越多,IO消耗越大

解決方案:

新增索引:

INDEX3 ( BATCHID, ACCOUNTID, VALIDRECORD)

=================== DB引擎自動選擇 INDEX3 作為索引 ===================

因為:

1. 其是覆蓋索引,複合索引的列涵蓋了所有搜尋列和條件列

2. 符合複合索引的最左原則

所以:

以INDEX RANGE SCAN執行

=================== 兩組實驗資料 ===================

env -> SIT HK HF

----- 第一組 -----
BATCHID2 = 'HK#ACCOUNT-BATCH#20180905#3df3e64a-1a42-4a73-9804-ba32813d2ea7' -> 326

INDEX1 COST = 10(索引查詢IO) + 305(回表IO) + 1(無序Group by的CPU佔用) = 316
INDEX2 COST = 4319(無引導列且覆蓋索引查詢IO) + 1(無序Group by的CPU佔用) = 4320
INDEX3 COST = 8(有引導列且覆蓋索引查詢IO) + 0(有序Group by的CPU佔用) = 8
no index COST = 67259(全表掃描IO) + 1(無序Group by的CPU佔用) = 67260

----- 第二組 -----
BATCHID1 = 'HK#ACCOUNT-BATCH#20190501#96732a40-aebe-4354-b83d-3c6f781c6df1' -> 231566

INDEX1 COST = 3510(索引查詢IO) + 213667(回表IO) + 1418(無序Group by的CPU佔用) = 218595
INDEX2 COST = 4319(無引導列且覆蓋索引查詢IO) + 1342(無序Group by的CPU佔用) = 5661
INDEX3 COST = 2870(有引導列且覆蓋索引查詢IO) + 0(有序Group by的CPU佔用) = 2870
no index COST = 67260(全表掃描IO) + 1341(無序Group by的CPU佔用) = 68610


=================== COST ===================
INDEX1 cost:索引查詢IO + 回表IO + 條件查詢CPU消耗

INDEX2 cost: 無引導列且覆蓋索引查詢IO + 條件查詢CPU消耗

INDEX3 cost: 有引導列且覆蓋索引查詢IO + 條件查詢CPU消耗

no index cost:全表掃描IO + 條件查詢CPU消耗

=================== 兩組實驗資料 ===================

----- 第一組 -----
BATCHID2 = 'HK#ACCOUNT-BATCH#20180905#3df3e64a-1a42-4a73-9804-ba32813d2ea7' -> 326

INDEX1 COST = 10(索引查詢IO) + 305(回表IO) + 1(無序Group by的CPU佔用) = 316
INDEX2 COST = 4319(無引導列且覆蓋索引查詢IO) + 1(無序Group by的CPU佔用) = 4320
INDEX3 COST = 8(有引導列且覆蓋索引查詢IO) + 0(有序Group by的CPU佔用) = 8
no index COST = 67259(全表掃描IO) + 1(無序Group by的CPU佔用) = 67260

----- 第二組 -----
BATCHID1 = 'HK#ACCOUNT-BATCH#20190501#96732a40-aebe-4354-b83d-3c6f781c6df1' -> 231566

INDEX1 COST = 3510(索引查詢IO) + 213667(回表IO) + 1418(無序Group by的CPU佔用) = 218595
INDEX2 COST = 4319(無引導列且覆蓋索引查詢IO) + 1342(無序Group by的CPU佔用) = 5661
INDEX3 COST = 2870(有引導列且覆蓋索引查詢IO) + 0(有序Group by的CPU佔用) = 2870
no index COST = 67260(全表掃描IO) + 1341(無序Group by的CPU佔用) = 68610