索引掃描的過程
1、例子:select id from big_table where id=42;(索引在ID上)
因為因為索引的高度是3,那麼一致性讀就是3,先讀了根塊,再讀枝塊,再讀葉塊,沒有回表。(索引=KEY+ROWID,這裡KEY就是ID=42)
如果是select * from big_table where id=42; 那麼一致性讀肯定大於3。
索引在邏輯上是順序的,物理上是隨機的。索引在物理上讀是分散的。但是索引在邏輯上讀是順序的。經常可以看到遮掩的等待:db file sequential read 這個就是順序讀,其實這裡就是讀索引等待。索引它不會要求我們按一種連續的方式讀取塊1、然後是塊2,接著是塊3.我們將以一種非常隨意的方式讀取和重新讀取塊。這種塊I/O 可能非常慢。
2、B*樹索引的掃描
唯一性掃描
INDEX KEY=XXX 就遍歷了樹的高度,如果是INDEX KEY > XXX AND INDEX KEY < YYYY,那是涉及索引範圍遍歷。
範圍掃描
範圍掃描先找到查詢的最小值,一直遍歷到索引鍵值的最大值,比如,a >50 and a<100。找50的話,就從根,到枝,再到葉,葉和葉節點之間,都有指標相連,這時候,我們就從50開始,再找兄弟葉節點
如果索引的碎片比較多的話,那麼範圍掃描非常慢。那麼就需要重建索引或者合併索引。
全索引掃描
找到索引第1個葉節點,一直掃描到最後一個葉節點
快速全索引掃描
掃描的索引反饋給使用者時沒有順序要求,這樣,我們可以物理的對索引塊進行順序訪問,這樣,我們可以實現索引塊的多塊讀。
前面的index full scan,我們簡稱ifs
後面這個index fast full scan,我們簡稱iffs
3、補充幾個概念:隨機訪問/順序訪問,離散讀/順序讀
當oracle程序需要訪問資料檔案裡的資料塊時,oracle會有兩種型別的I/O操作方式:
隨機訪問:每次讀取一個數據塊(通過等待事件“db file sequential read”順序讀體現出來)。
順序訪問:每次讀取多個數據塊(通過等待事件“db file scattered read”隨機讀體現出來)。
第一種方式則是訪問索引裡的資料塊,而第二種方式的I/O操作屬於全表掃描。這裡順帶有一個問題,為何隨機訪問會對應到db file sequential read等待事件,而順序訪問則會對應到db file scattered read等待事件呢?這似乎反過來了,隨機訪問才應該是分散(scattered)的,而順序訪問才應該是順序(sequential)的。其實,等待事件主要根據實際獲取物理I/O塊的方式來命名的,而不是根據其在I/O子系統的邏輯方式來命名的。下面對於如何獲取索引資料塊的方式中會對此進行說明。
我們看到前面對B樹索引的體系結構的描述,可以知道其為一個樹狀的立體結構。其對應到資料檔案裡的排列當然還是一個平面的形式,也就是像下面這樣。因此,當oracle需要訪問某個索引塊的時候,勢必會在這個結構上跳躍的移動。
/根/分支/分支/葉子/…/葉子/分支/葉子/葉子/…/葉子/分支/葉子/葉子/…/葉子/分支/.....
當oracle需要獲得一個索引塊時,首先從根節點開始,根據所要查詢的鍵值,從而知道其所在的下一層的分支節點,然後訪問下一層的分支節點,再次同樣根據鍵值訪問再下一層的分支節點,如此這般,最終訪問到最底層的葉子節點。可以看出,其獲得物理I/O塊時,是一個接著一個,按照順序,序列進行的。在獲得最終物理塊的過程中,我們不能同時讀取多個塊,因為我們在沒有獲得當前塊的時候是不知道接下來應該訪問哪個塊的。因此,在索引上訪問資料塊時,會對應到db file sequential read等待事件,其根源在於我們是按照順序從一個索引塊跳到另一個索引塊,從而找到最終的索引塊的。
那麼對於全表掃描來說,則不存在訪問下一個塊之前需要先訪問上一個塊的情況。全表掃描時,oracle知道要訪問所有的資料塊,因此唯一的問題就是儘可能高效的訪問這些資料塊。因此,這時oracle可以採用同步的方式,分幾批,同時獲取多個數據塊。這幾批的資料塊在物理上可能是分散在表裡的,因此其對應到db file scattered read等待事件。