PostgreSQL 索引訪問(wèn)方法函數(shù)

2021-09-15 11:04 更新

索引訪問(wèn)方法必須在IndexAmRoutine中提供的索引構(gòu)造和維護(hù)函數(shù)有:

IndexBuildResult *
ambuild (Relation heapRelation,
         Relation indexRelation,
         IndexInfo *indexInfo);

創(chuàng)建一個(gè)新索引。索引關(guān)系已經(jīng)被物理創(chuàng)建,但是是空的。必須用索引訪問(wèn)方法要求的固定數(shù)據(jù)填充它,外加所有已經(jīng)在表里的行的項(xiàng)。通常,ambuild函數(shù)會(huì)調(diào)用table_index_build_scan()來(lái)掃描表以獲取現(xiàn)有元組并計(jì)算需要被插入到索引的鍵。該函數(shù)必須返回一個(gè)已分配內(nèi)存的結(jié)構(gòu),其中包含關(guān)于新索引的統(tǒng)計(jì)信息。

void
ambuildempty (Relation indexRelation);

構(gòu)建一個(gè)空索引,并且把它寫入到給定關(guān)系的初始化分叉中( INIT_FORKNUM)。只會(huì)為不做日志的索引調(diào)用這個(gè)方法,被寫入到 初始化分叉的空索引在每次服務(wù)器啟動(dòng)時(shí)將被復(fù)制到主關(guān)系分叉中。

bool
aminsert (Relation indexRelation,
          Datum *values,
          bool *isnull,
          ItemPointer heap_tid,
          Relation heapRelation,
          IndexUniqueCheck checkUnique,
          IndexInfo *indexInfo);

向現(xiàn)有索引插入一個(gè)新元組。valuesisnull數(shù)組給出需要被索引的鍵值,而heap_tid是要被索引的 TID。 如果該訪問(wèn)方法支持唯一索引(它的amcanunique標(biāo)志為真),那么checkUnique指示要執(zhí)行的唯一性檢查類型。這根據(jù)唯一約束是否為可推遲的而變化,詳見(jiàn) 第 61.5 節(jié)。通常在執(zhí)行唯一性檢查時(shí)訪問(wèn)方法僅需要heapRelation參數(shù)(因?yàn)槟菚r(shí)它將不得不到堆中驗(yàn)證元組的存活性)。

該函數(shù)的布爾結(jié)果值僅僅在checkUniqueUNIQUE_CHECK_PARTIAL時(shí)才有意義。這種情況下一個(gè)“真”結(jié)果意味著這個(gè)新項(xiàng)是已知唯一的,反之“假”結(jié)果意味著它可能不 是唯一的(并且一個(gè)延遲的唯一性校驗(yàn)必須是預(yù)定的)。對(duì)于其他情況,建議使用一個(gè)常量“假”結(jié)果。

有些索引可能不會(huì)索引所有元組。如果元組不被索引,aminsert應(yīng)該僅返回而什么都不做。

如果索引AM希望在SQL語(yǔ)句中連續(xù)的索引插入之間緩沖數(shù)據(jù),它可以在indexInfo->ii_Context中分配空間并且在indexInfo->ii_AmCache(初始為NULL)中存放一個(gè)指向該數(shù)據(jù)的指針。

IndexBulkDeleteResult *
ambulkdelete (IndexVacuumInfo *info,
              IndexBulkDeleteResult *stats,
              IndexBulkDeleteCallback callback,
              void *callback_state);

從索引中刪除元組。這是一個(gè)批量刪除操作,它的意圖是通過(guò)掃描整個(gè)索引并檢查每個(gè)項(xiàng)看它是否需要被刪除。被傳遞進(jìn)來(lái)的callback函數(shù)必須被調(diào)用(調(diào)用風(fēng)格是:callback(TID , callback_state) returns bool)來(lái)判斷任何其引用的 TID 標(biāo)識(shí)的索引項(xiàng)是否需要?jiǎng)h除。必須返回 NULL 或者是一個(gè) palloc 過(guò)的、 包含刪除操作效果的統(tǒng)計(jì)信息的結(jié)構(gòu)。如果不需要向amvacuumcleanup傳遞信息,返回 NULL 也是 OK 的。

由于maintenance_work_mem被限制,在刪除多行的時(shí)候ambulkdelete可能需要被調(diào)用多次。stats參數(shù)是對(duì)這個(gè)索引上一次調(diào)用的結(jié)果(在一個(gè)VACUUM操作中第一次調(diào)用時(shí)是 NULL)。這將允許 AM 在整個(gè)操作過(guò)程中積累統(tǒng)計(jì)信息。典型的,如果被傳遞的 stats非空,ambulkdelete將會(huì)修改并返回相同的結(jié)構(gòu)。

IndexBulkDeleteResult *
amvacuumcleanup (IndexVacuumInfo *info,
                 IndexBulkDeleteResult *stats);

在一個(gè)VACUUM操作(零個(gè)或更多次ambulkdelete調(diào)用)后清空。雖然不必做任何返回索引統(tǒng)計(jì)信息之外的事情,但是它可能執(zhí)行批量清理,例如回收空索引頁(yè)面。stats是最后一次ambulkdelete 調(diào)用返回的東西或者 NULL(如果沒(méi)有元組需要?jiǎng)h除而未調(diào)用 ambulkdelete)。如果結(jié)果不是 NULL,那么它必須是一個(gè)已經(jīng)被 palloc 的結(jié)構(gòu)。它包含的統(tǒng)計(jì)信息將用于更新pg_class并且由VACUUM報(bào) 告(如果給出了VERBOSE)。如果索引在VACUUM操作期間根本沒(méi)有改變,那么返回 NULL 也是可以的,否則必須返回正確的統(tǒng)計(jì)信息。

PostgreSQL 8.4 開(kāi)始,amvacuumcleanup將也會(huì)在一個(gè)ANALYZE操作結(jié)束時(shí)被調(diào)用。這種情況中stats總是 NULL 并且任何返回值都將會(huì)被忽略。這種情況可以通過(guò)檢測(cè)info->analyze_only來(lái)區(qū)分。我們建議,在這樣的調(diào)用中訪問(wèn)方法除了做插入后的清理之外什么也不做,并且那是僅僅是在一個(gè)自動(dòng)清理工作者進(jìn)程中。

bool
amcanreturn (Relation indexRelation, int attno);

通過(guò)返回型為一個(gè)IndexTuple的索引項(xiàng)的被索引列值,檢查索引是否能在給定列上支持只用索引的掃描。屬性編號(hào)從 1 開(kāi)始編號(hào),即第一列的 attno 是 1。如果支持返回 TRUE,否則返回 FALSE。如果訪問(wèn)方法 完全不支持只用索引的掃描,其IndexAmRoutine結(jié)構(gòu)中的amcanreturn域可以被設(shè)置為 NULL。

void
amcostestimate (PlannerInfo *root,
                IndexPath *path,
                double loop_count,
                Cost *indexStartupCost,
                Cost *indexTotalCost,
                Selectivity *indexSelectivity,
                double *indexCorrelation,
                double *indexPages);

估計(jì)一次索引掃描的開(kāi)銷。這個(gè)函數(shù)在下面的第 61.6 節(jié)中有完整的討論。

bytea *
amoptions (ArrayType *reloptions,
           bool validate);

分析和驗(yàn)證一個(gè)索引的 reloptions 數(shù)組。僅當(dāng)一個(gè)索引存在非空 reloptions 數(shù)組時(shí)才會(huì)被調(diào)用。reloptions是一個(gè)text數(shù)組,包含name=value形式的項(xiàng)。 該函數(shù)應(yīng)當(dāng)構(gòu)建一個(gè)bytea值,該值將被拷貝進(jìn)索引的 relcache 項(xiàng)的rd_options域。bytea值的數(shù)據(jù)內(nèi)容是開(kāi)放由訪問(wèn)方法定義的, 大部分的標(biāo)準(zhǔn)訪問(wèn)方法都使用StdRdOptions結(jié)構(gòu)。當(dāng)validate為真時(shí),如果任何一個(gè)選項(xiàng)都不可識(shí)別或者含有非法值,該函數(shù)都應(yīng)當(dāng)報(bào)告一個(gè)適當(dāng)?shù)腻e(cuò)誤消息;當(dāng) validate 為假時(shí),非法 項(xiàng)應(yīng)該被安靜地忽略(當(dāng)正在載入的選項(xiàng)已經(jīng)在pg_catalog中時(shí), validate為假;僅在訪問(wèn)方法已經(jīng)改變了選項(xiàng)的規(guī)則時(shí)才可能找 到非法項(xiàng),并且在此情況下忽略廢棄的項(xiàng)是合適的)。如果想要默認(rèn)行為,那么返回 NULL 也 OK。

bool
amproperty (Oid index_oid, int attno,
            IndexAMProperty prop, const char *propname,
            bool *res, bool *isnull);

amproperty方法允許索引方法覆蓋pg_index_column_has_property和相關(guān)函數(shù)的默認(rèn)行為。如果訪問(wèn)方法對(duì)于索引性質(zhì)查詢沒(méi)有指定特殊的行為,其IndexAmRoutine結(jié)構(gòu)的amproperty域可以被設(shè)置為 NULL。否則,對(duì)于 pg_indexam_has_property調(diào)用會(huì)使用均為 0 的index_oidattno參數(shù)來(lái)調(diào)用amproperty方法;對(duì)于pg_index_has_property調(diào)用會(huì)使用有效的index_oid和為 0 的attno參數(shù)來(lái)調(diào)用amproperty方法;對(duì)于pg_index_column_has_property調(diào)用會(huì)使用有效的index_oid以及大于零的attno參數(shù)來(lái)調(diào)用 amproperty方法。prop是用于標(biāo)識(shí)被測(cè)試性質(zhì)的枚舉值,而propname是原始的性質(zhì)名稱字符串。如果核心代碼不能識(shí)別該性質(zhì)名稱,則propAMPROP_UNKNOWN。訪問(wèn)方法可以通過(guò)檢查 propname 是否匹配(為與核心代碼一致,使用pg_strcasecmp來(lái)匹配)來(lái)定義自定義性質(zhì)名稱;對(duì)于核心代碼已知的名稱,最好檢查prop。 如果amproperty方法返回true則表示它已經(jīng)確定了性質(zhì)測(cè)試的結(jié)果:它必定會(huì)設(shè)置*res為要返回的布爾值,如果要返回 NULL 則設(shè)置*isnulltrue(兩個(gè)被引用的變量在調(diào)用之前要被初始化為false)。如果amproperty方法返回false則核心代碼將會(huì)用其通常的邏輯來(lái)確定性質(zhì)測(cè)試的結(jié)果。

支持排序操作符的訪問(wèn)方法應(yīng)該實(shí)現(xiàn)AMPROP_DISTANCE_ORDERABLE性質(zhì)測(cè)試,因?yàn)楹诵拇a不知道如何做該測(cè)試并且會(huì)返回 NULL。如果有比打開(kāi)索引并調(diào)用amcanreturn(這是核心代碼的默認(rèn)行為)更廉價(jià)的方法來(lái)做AMPROP_RETURNABLE測(cè)試,最好也實(shí)現(xiàn)它。默認(rèn)行為應(yīng)該對(duì)所有其他標(biāo)準(zhǔn)性質(zhì)是符合要求的。

char *
ambuildphasename (int64 phasenum);

返回給定構(gòu)建相數(shù)號(hào)碼的文本名稱。 相數(shù)號(hào)碼是在通過(guò)pgstat_progress_update_param 接口構(gòu)建索引期間報(bào)告的. 然后相數(shù)號(hào)碼在pg_stat_progress_create_index視圖中公開(kāi)。

bool
amvalidate (Oid opclassoid);

只要訪問(wèn)方法能夠,為指定的操作符類驗(yàn)證系統(tǒng)目錄項(xiàng)。例如,這可能包括所有所需支持函數(shù)所提供的測(cè)試。如果該 opclass 不合法,amvalidate函數(shù)必須返回假。所存在的問(wèn)題應(yīng)由ereport消息報(bào)告。

當(dāng)然,索引的目的是支持掃描那些匹配一個(gè)可索引WHERE情況的元組,常常也被稱為限定詞掃描鍵。索引掃描的語(yǔ)義在下面的第 61.3 節(jié)中有完整的描述。一個(gè)索引訪問(wèn)方法可以支持 普通索引掃描、位圖索引掃描或者兩者。一個(gè)索引訪問(wèn)方法必須或可能提供的與掃描相關(guān)的函數(shù)是:

IndexScanDesc
ambeginscan (Relation indexRelation,
             int nkeys,
             int norderbys);

為一個(gè)索引掃描做準(zhǔn)備。nkeysnorderbys參數(shù)說(shuō)明要被用在掃描中的條件和排序操作符的數(shù)目,它們可以用于空間分配目的。注意掃描鍵的實(shí)際值還沒(méi)有被提供。結(jié)果必須是一個(gè) palloc 過(guò)的結(jié)構(gòu)。由于實(shí)現(xiàn)的原因,索引訪問(wèn)方法必須通過(guò)調(diào)用RelationGetIndexScan()來(lái)創(chuàng)建這個(gè)結(jié)構(gòu)。在大多數(shù)情況中, ambeginscan除了做這個(gè)調(diào)用和獲取鎖之外不會(huì)做很多工作,索引掃描啟動(dòng)中有趣的部分在amrescan中。

void
amrescan (IndexScanDesc scan,
          ScanKey keys,
          int nkeys,
          ScanKey orderbys,
          int norderbys);

開(kāi)始或者重新開(kāi)始一個(gè)索引掃描,可能使用的是一個(gè)新的掃描鍵(要想使用之前傳遞的鍵重新開(kāi)始,給keys 和/或orderbys傳遞 NULL)。請(qǐng)注意,使用的鍵或排序操作符的個(gè)數(shù)不能大于傳遞給ambeginscan的個(gè)數(shù)。實(shí)際上這個(gè)重新開(kāi)始特性的使用場(chǎng)景是:在一個(gè)嵌套循環(huán)連接選取了一個(gè)新的 outer 元組時(shí),因此需要一個(gè)新的鍵比較值,但掃描鍵結(jié)構(gòu)仍然保持相同。

boolean
amgettuple (IndexScanDesc scan,
            ScanDirection direction);

在給定掃描中取下一個(gè)元組,向給定方向移動(dòng)(在索引中向前或者向后)。如果取到了元組,則返回 TRUE,如果取到匹配的元組,返回 FALSE。在 TRUE 的情況中,該元組的 TID 被存儲(chǔ)在scan結(jié)構(gòu)中。請(qǐng)注意成功只 意味著索引包含一個(gè)匹配掃描鍵的項(xiàng),并不意味該元組仍然在堆中存在, 或者是能夠通過(guò)調(diào)用者的快照測(cè)試。在成功時(shí), amgettuple也必須把scan->xs_recheck設(shè) 置成 TRUE 或者 FALSE。FALSE 意味著它確定索引項(xiàng)匹配掃描鍵。TRUE 意味著它并不確定,而且必須在取得堆元組之后對(duì)它重新檢查掃描鍵表示的條件。 這條規(guī)定支持有損的索引操作符。注意重新檢查僅僅對(duì)掃描條件擴(kuò)展;一個(gè)部分索引謂語(yǔ)(如果有)從不被 amgettuple調(diào)用者重新檢查。

如果索引支持只用索引掃描(即amcanreturn對(duì)它返回 TRUE),則在成功時(shí) AM 也必須檢查scan->xs_want_itup,并且如果檢查為真它必須返回索引項(xiàng)的原始被索引數(shù)據(jù)。該數(shù)據(jù)的返回形式可以是一個(gè)存儲(chǔ)在 scan->xs_itup中的IndexTuple指針外加元組描述符scan->xs_itupdesc,或者是一個(gè)存儲(chǔ)在scan->xs_hitup中的HeapTuple指針外加元組描述符scan->xs_hitupdesc(在重構(gòu)可能無(wú)法放在一個(gè) IndexTuple中的數(shù)據(jù)時(shí),應(yīng)該使用后一種格式)。不管是哪種形式,訪問(wèn)方法應(yīng)該負(fù)責(zé)管理好指針引用的數(shù)據(jù)。至少在為掃描下一次調(diào)用amgettuple、amrescanamendscan之前,該數(shù)據(jù)必須是完好的。

如果訪問(wèn)方法支持普通索引掃描,只需要提供amgettuple函數(shù)。如果不支持,它的IndexAmRoutine結(jié)構(gòu)的amgettuple域必須被設(shè)置為 NULL。

int64
amgetbitmap (IndexScanDesc scan,
             TIDBitmap *tbm);

在給定掃描中取所有元組并且把它們添加到調(diào)用者提供的TIDBitmap中(即,把元組 ID 的集合 OR 到已經(jīng)存在于位圖中的東西里面)。返回被取得的元組的數(shù)量(這可能僅僅是一個(gè)近似計(jì)數(shù),例如一些 AM 不會(huì)去重)。在把元組 ID 插入到位圖時(shí),amgetbitmap可以指明對(duì)指定元組 ID 要求重新檢查掃描條件。這與amgettuplexs_recheck輸出參數(shù)類似。注意:在當(dāng)前的實(shí)現(xiàn)中,這個(gè)特性的支持是和對(duì)位圖本身有損存儲(chǔ)的支持合并在一起的,并且調(diào)用者會(huì)對(duì)可重新檢查的元組檢查掃描條件和部分索引謂詞(如果有)。但是,那不會(huì)總是真的。amgetbitmapamgettuple不能被用于同一個(gè)索引掃描;正如第 61.3 節(jié)中所解釋的,在使用 amgetbitmap時(shí)也有其他的限制條件。

如果訪問(wèn)方法支持bitmap索引掃描,則僅需要提供amgetbitmap函數(shù)。如果不支持,它的IndexAmRoutine結(jié)構(gòu)中的amgetbitmap域必須被設(shè)置為 NULL。

void
amendscan (IndexScanDesc scan);

結(jié)束掃描并釋放資源。不應(yīng)該釋放scan結(jié)構(gòu)本身,但訪問(wèn)方法內(nèi)部使用的任何鎖或者 pin 都應(yīng)該被釋放, 以及ambeginscan和其他掃描相關(guān)函數(shù)分配的任何其他內(nèi)存。

void
ammarkpos (IndexScanDesc scan);

標(biāo)記當(dāng)前掃描位置。訪問(wèn)方法只需要支持每個(gè)掃描里面有一個(gè)被標(biāo)記的掃描位置。

ammarkpos函數(shù)只有在訪問(wèn)方法支持有序掃描時(shí)才需要提供。如果不支持,則訪問(wèn)方法的IndexAmRoutine結(jié)構(gòu)的ammarkpos域可以設(shè)置為 NULL。

void
amrestrpos (IndexScanDesc scan);

把掃描恢復(fù)到最近標(biāo)記的位置。

amrestrpos函數(shù)只有在訪問(wèn)方法支持有序掃描時(shí)才需要提供。如果不支持,則訪問(wèn)方法的IndexAmRoutine結(jié)構(gòu)的amrestrpos域可以設(shè)置為 NULL。

除了支持普通的索引掃描之外,某些類型的索引可能希望支持并行索引掃描,這種方式允許多個(gè)后端合作來(lái)執(zhí)行一次索引掃描。索引訪問(wèn)方法應(yīng)該安排好各種事情,這樣每個(gè)參與合作的進(jìn)程才能返回原本會(huì)由普通非并行索引掃描執(zhí)行得到的元組的一個(gè)子集,但是得到的那些子集的并集應(yīng)該等于普通非并行索引掃描得到的元組集合。此外,雖然不需要并行掃描返回的元組有任何全局順序,但每個(gè)參與合作的后端中返回的元組子集的順序必須匹配所要求的順序。必須實(shí)現(xiàn)下列函數(shù)才能支持并行索引掃描:

Size
amestimateparallelscan (void);

估算并且返回訪問(wèn)方法執(zhí)行一次并行掃描所需要的動(dòng)態(tài)共享內(nèi)存的字節(jié)數(shù)(這個(gè)數(shù)字是對(duì)ParallelIndexScanDescData中訪問(wèn)方法無(wú)關(guān)的數(shù)據(jù)所需空間量的補(bǔ)充而不是替代)。

對(duì)于不支持并行掃描或者額外存儲(chǔ)需求的的字節(jié)數(shù)為零的訪問(wèn)方法,無(wú)需實(shí)現(xiàn)這個(gè)函數(shù)。

void
aminitparallelscan (void *target);

在一次并行掃描的開(kāi)頭將調(diào)用這個(gè)函數(shù)來(lái)初始化動(dòng)態(tài)共享內(nèi)存。target將指向一段動(dòng)態(tài)共享內(nèi)存空間,其大小至少為之前amestimateparallelscan返回的字節(jié)數(shù),并且這個(gè)函數(shù)可以使用這部分空間來(lái)存放它希望存放的任何數(shù)據(jù)。

對(duì)于不支持并行掃描或者不要求初始化共享內(nèi)存空間的情況,無(wú)需實(shí)現(xiàn)這個(gè)函數(shù)。

void
amparallelrescan (IndexScanDesc scan);

如果實(shí)現(xiàn)了這個(gè)函數(shù),當(dāng)并行索引掃描必須被重啟時(shí),將會(huì)調(diào)用這個(gè)函數(shù)。它應(yīng)該重置由aminitparallelscan建立的任何共享狀態(tài),這樣掃描將會(huì)被重頭重新開(kāi)始。


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)