PostgreSQL 索引掃描

2021-09-15 11:04 更新

在一個索引掃描中,索引訪問方法負責(zé)提供它拿到的匹配掃描鍵的所有元組的TID。訪問方法會涉及從索引的父表中實際取得那些元組,也不會涉及判斷它們是否通過了掃描的可見性測試或者是其它條件。

一個掃描鍵是一個WHERE子句的內(nèi)部表示,WHERE子句的形式是index_key operator constant,其中索引鍵字索引中的一個列,而操作符是和該索引列相關(guān)聯(lián)的操作符族的一個成員。一個索引掃描擁有零個或者多個掃描鍵,它們是隱式 AND 關(guān)系 — 返回的元組被認為滿足所有列出的條件。

對于一個特定查詢,訪問方法可能報告索引是有損的或者要求重新檢查。這就暗示著該索引掃 描會返回所有通過掃描鍵的項,外加上一些可能沒通過掃描鍵的項。核心系統(tǒng)的索引掃描機制然后就會再次在堆元組上應(yīng)用索引條件來驗證它是否真地應(yīng)該被選擇。如果沒有指定重新檢查選項,索引掃描必須返回準(zhǔn)確的匹配項集合。

請注意,確保找到所有(只有)通過所有給定掃描鍵的條目的工作完全由訪問方法負責(zé)。還有,核心系統(tǒng)將只是簡單地 放過所有匹配掃描鍵和操作符族的WHERE子句,而不會做任何語義分析來判斷它們是否冗余或者矛盾。例如,給定WHERE x > 4 AND x > 14(其中x是一個 B-樹 索引列,它被留給 B-樹 amrescan函數(shù)來發(fā)現(xiàn)第一個掃描鍵是冗余并且可以被丟棄。amrescan期間需要的預(yù)處理的范圍將取決于索引訪問方法需要什么來把掃描鍵縮減為一種正規(guī)化的形式。

一些訪問方法按照一個良定義的順序來返回索引項,其他的則不會。實際上一個訪問方法可以有兩種不同的方式支持排序輸出:

  • 總是按數(shù)據(jù)的自然序返回項的訪問方法應(yīng)該設(shè)置amcanorder為真。當(dāng)前,這樣的訪問方法必須對它們的等值和排序操作符使用b-tree兼容的策略號。

  • 支持排序操作符的訪問方法應(yīng)該設(shè)置amcanorderbyop為真。這表示索引有能力按照滿足ORDER BY index_key operator constant的一種順序返回項。如前所述,這種形式的掃描修飾符可以被傳遞給 amrescan。

amgettuple函數(shù)有一個direction參數(shù),它可以是 ForwardScanDirection(正常情況)或者BackwardScanDirection。如果amrescan之后的第一次調(diào)用指定了 BackwardScanDirection,那么匹配條件的索引項集合是從后向前掃描的,而 不是通常的從前向后掃描,因此amgettuple必須返回索引中最后一個匹配元組,而不是通常情況下的第一個(這只對設(shè)置了amcanorder為真訪問方法發(fā)生)。在第一次調(diào)用后,amgettuple必須被準(zhǔn)備好從最近被返回項的位置按照任何一種方向推進掃描(但是如果 amcanbackward為假,所有后續(xù)調(diào)用將使用第一次相同的方向)。

支持排序掃描的訪問方法必須支持在掃描里標(biāo)記一個位置并且隨后返回到這個標(biāo)記過的位置。同一個位置可能會被重復(fù)多次還原。但是,每個掃描中只有一個位置需要被記??;一個新的ammarkpos調(diào)用將重寫之前標(biāo)記的位置。一個不支持排序掃描的訪問方法無需在IndexAmRoutine中提供 ammarkposamrestrpos函數(shù),把這些指針設(shè)置為 NULL 即可。

掃描位置和標(biāo)記位置(如果存在))都必須在面對索引中的并發(fā)插入和刪除時保持一致性。如果一個新插入的項并未被一個掃描返回(如果該掃描開始的時候該項已經(jīng)存在,該掃描將已經(jīng)找到該項),或者說掃描通過重新掃描或者反向掃描返回這樣一個項(即使它第一次沒有返回這樣一個項),這些情況都是可以接受的。類似的還有,一個并發(fā)的刪除可能或不可能被反映在一個掃描的結(jié)果中。重要的是,插入或者刪除不會導(dǎo)致掃描錯過或者多次返回本身不是被插入或者刪除的項。

如果索引存儲原始被索引的數(shù)據(jù)值(并且不是它們的某種有損表示),它可用來支持只用索引的掃描,著這種掃描中索引返回的就是實際的數(shù)據(jù)而不只是堆元組的 TID。這只有在可見性映射顯示該 TID 位于一個全部可見的頁面時才能避免 I/O;否則必須訪問堆元組來檢查 MVCC 可見性。但是這就不用訪問方法操心了。

除了使用amgettuple,一個索引掃描可以通過amgetbitmap在一次調(diào)用中取得所有元組來完成。這樣做可能會比amgettuple有顯著的效率提升,因為它可以避免在訪問方法內(nèi)的加鎖/解鎖循環(huán)。原則上amgetbitmap應(yīng)該和重復(fù)調(diào)用amgettuple的效果相同, 不過我們強加了一些限制來簡化這件事。首先,amgetbitmap一次返回 所有元組并且標(biāo)記并且不支持標(biāo)記或恢復(fù)掃描位置。第二,在一個位圖中返回的元組沒有任何指定的順序,這也是為什么amgetbitmap沒有一個direction參數(shù)的原因(排序操作符也將永遠不會提供給這種掃描)。還有,對于使用amgetbitmap的只用索引掃描沒有規(guī)定,因為沒有辦法返回索引元組的內(nèi)容。最后,如 第 61.4 節(jié)中所說的,amgetbitmap不保證被返回元組上的任何鎖。

注意如果訪問方法的內(nèi)部實現(xiàn)不適合一個 API 或其他 API,允許一個訪問方法只實現(xiàn)amgetbitmap而不實現(xiàn)amgettuple,或者反過來。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號