一文講透如何看懂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