W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
SP-GiST提供了一個(gè)高抽象層次的接口,要求訪問(wèn)方法開(kāi)發(fā)者實(shí)現(xiàn)與一個(gè)給定數(shù)據(jù)類(lèi)型相關(guān)的幾種方法。SP-GiST核心負(fù)責(zé)高效的磁盤(pán)映射和搜索樹(shù)結(jié)構(gòu)。它也會(huì)處理并發(fā)和日志。
SP-GiST樹(shù)的葉子元組包含與被索引列數(shù)據(jù)類(lèi)型相同的值。在根層的葉子元組總是包含原始的被索引數(shù)據(jù)值,但是在較下層的葉子元組可能只含有一個(gè)壓縮后的表示,例如一個(gè)后綴。在這種情況下,操作符類(lèi)支持函數(shù)必須能夠使用從內(nèi)部元組計(jì)算出來(lái)的信息重構(gòu)出原始的值,這些內(nèi)部元組指的是在到達(dá)葉子層的過(guò)程中穿過(guò)的元組。
內(nèi)部元組更加復(fù)雜,因?yàn)樗鼈兪撬阉鳂?shù)的分支點(diǎn)。每一個(gè)內(nèi)部元組包含一個(gè)或者更多個(gè)結(jié)點(diǎn),結(jié)點(diǎn)表示一個(gè)具有相似葉子值的組。一個(gè)結(jié)點(diǎn)包含一個(gè)向下的鏈接,這個(gè)鏈接可以導(dǎo)向另一個(gè)較下層的內(nèi)部元組,或者是由位于同一索引頁(yè)面的葉子元組組成的一個(gè)短列表。每一個(gè)結(jié)點(diǎn)通常還有一個(gè)標(biāo)簽來(lái)描述它,例如,在一個(gè) radix 樹(shù)中結(jié)點(diǎn)標(biāo)簽可以是串值的下一個(gè)字符(或者,如果一種操作符類(lèi)對(duì)于所有內(nèi)部元組使用一個(gè)固定的節(jié)點(diǎn)集合,則它可以省略節(jié)點(diǎn)標(biāo)簽,見(jiàn) 第 65.4.2 節(jié))??蛇x地,一個(gè)內(nèi)部元組可以有一個(gè)前綴值來(lái)描述它所有的成員。在一個(gè) radix 樹(shù)中前綴可以是所表示的串的公共前綴。前綴值并不一定非要是一個(gè)真正的前綴,它可以是操作符類(lèi)需要的任何數(shù)據(jù)。例如,在一個(gè)四叉樹(shù)中它可以存儲(chǔ)用于劃分四個(gè)象限的中心點(diǎn)。一個(gè)四叉樹(shù)的內(nèi)部元組則可以包含對(duì)應(yīng)于圍繞該中心點(diǎn)的象限的四個(gè)結(jié)點(diǎn)。
某些樹(shù)算法要求當(dāng)前元組所在層(或深度)的知識(shí),因此SP-GiST核心為操作符類(lèi)提供了機(jī)會(huì)以便在沿著樹(shù)下降時(shí)管理層計(jì)數(shù)。當(dāng)需要重組被表示的值時(shí),這也可以為增量地重構(gòu)過(guò)程提供支持,這還可以為沿著樹(shù)下降時(shí)向下層傳遞附加數(shù)據(jù)(稱(chēng)為貫穿值)提供支持。
SP-GiST核心代碼會(huì)關(guān)注空項(xiàng)。盡管SP-GiST索引確實(shí)可以存儲(chǔ)被索引列中的空值,但這對(duì)索引操作符類(lèi)代碼是隱藏的:不會(huì)有空索引項(xiàng)或搜索條件會(huì)被傳遞給操作符類(lèi)方法(我們假定SP-GiST操作符是嚴(yán)格的并且因此無(wú)法成功處理空值)。因此這里不會(huì)進(jìn)一步討論空值。
一個(gè)SP-GiST的索引操作符類(lèi)必須提供五個(gè)用戶定義的方法,并且兩個(gè)是可選的。所有五個(gè)強(qiáng)制的方法都接受兩個(gè)internal
參數(shù),其中第一個(gè)是一個(gè)指針,它指向一個(gè)包含用于支持方法的值的 C 結(jié)構(gòu)。而第二個(gè)參數(shù)也是一個(gè)指針,它指向?qū)⒎胖幂敵鲋档?C 結(jié)構(gòu)。其中四個(gè)強(qiáng)制的函數(shù)只返回void
,因?yàn)樗鼈兊乃薪Y(jié)果都出現(xiàn)在輸出結(jié)構(gòu)中。但是
leaf_consistent
會(huì)返回一個(gè)boolean
結(jié)果。這些方法不能修改它們的輸入結(jié)構(gòu)的任何域。在所有情況下,調(diào)用用戶定義的方法之前輸出結(jié)構(gòu)都被初始化為零??蛇x的第六個(gè)方法compress
接受要被索引的datum
作為唯一的參數(shù)并且返回適合于在葉子元組中物理存儲(chǔ)的值。可選的第七個(gè)方法 options
接受一個(gè)指向
C 結(jié)構(gòu)的 internal
指針,其中應(yīng)放置 opclass 特定的參數(shù),并返回 void
。
五個(gè)強(qiáng)制的用戶定義的方法是:
config
返回關(guān)于索引實(shí)現(xiàn)的靜態(tài)信息,包括前綴的數(shù)據(jù)類(lèi)型的OID以及結(jié)點(diǎn)標(biāo)簽數(shù)據(jù)類(lèi)型。
這個(gè)函數(shù)的SQL聲明必須看起來(lái)像這樣:
CREATE FUNCTION my_config(internal, internal) RETURNS void ...
第一個(gè)參數(shù)是一個(gè)指向spgConfigIn
C 結(jié)構(gòu)的指針,包含該函數(shù)的輸入數(shù)據(jù)。第二個(gè)參數(shù)是一個(gè)指向spgConfigOut
C 結(jié)構(gòu)的指針,函數(shù)必須將結(jié)果數(shù)據(jù)填充在其中。
typedef struct spgConfigIn
{
Oid attType; /* 要被索引的數(shù)據(jù)類(lèi)型 */
} spgConfigIn;
typedef struct spgConfigOut
{
Oid prefixType; /* 內(nèi)部元組前綴的數(shù)據(jù)類(lèi)型 */
Oid labelType; /* 內(nèi)部元組結(jié)點(diǎn)標(biāo)簽的數(shù)據(jù)類(lèi)型 */
Oid leafType; /* 葉子元組值的數(shù)據(jù)類(lèi)型 */
bool canReturnData; /* 操作符類(lèi)能重構(gòu)原始數(shù)據(jù) */
bool longValuesOK; /* 操作符類(lèi)能處理值 > 1 頁(yè) */
} spgConfigOut;
為了支持多態(tài)的索引操作符類(lèi),attType
要被傳入;對(duì)于普通固定數(shù)據(jù)類(lèi)型的操作符類(lèi),它將總是取相同的值,因此可以被忽略。
對(duì)于不使用前綴的操作符類(lèi),prefixType
可以被設(shè)置為VOIDOID
。同樣,對(duì)于不使用結(jié)點(diǎn)標(biāo)簽的操作符類(lèi),labelType
可以被設(shè)置為VOIDOID
。如果操作符類(lèi)能夠重構(gòu)出原來(lái)提供的被索引值,則canReturnData
應(yīng)該被設(shè)置為真。只有當(dāng)
attType
是變長(zhǎng)的并且操作符類(lèi)能夠?qū)㈤L(zhǎng)值通過(guò)反復(fù)的添加后綴分段時(shí),longValuesOK
才應(yīng)當(dāng)被設(shè)置為真(參見(jiàn)第 65.4.1 節(jié))。
leafType
通常和attType
相同。為了向后兼容性的原因,方法config
可以將leafType
保留成未初始化的形態(tài),那樣會(huì)得到與把leafType
設(shè)置為等于
attType
時(shí)一樣的效果。當(dāng)attType
與leafType
不同時(shí),可選的方法compress
必須被提供。方法compress
負(fù)責(zé)把要被索引的數(shù)據(jù)從attType
轉(zhuǎn)換為
leafType
。注意:兩種一致函數(shù)都會(huì)得到未更改的scankeys
,也不會(huì)使用compress
轉(zhuǎn)換。
choose
為將一個(gè)新值插入到一個(gè)內(nèi)部元組選擇一種方法。
該函數(shù)的SQL聲明必須看起來(lái)像這樣:
CREATE FUNCTION my_choose(internal, internal) RETURNS void ...
第一個(gè)參數(shù)是一個(gè)指向spgChooseIn
C 結(jié)構(gòu)的指針,包含該函數(shù)的輸入數(shù)據(jù)。第二個(gè)參數(shù)是一個(gè)指向spgChooseOut
C 結(jié)構(gòu)的指針,函數(shù)必須將結(jié)果數(shù)據(jù)填充在其中。
typedef struct spgChooseIn
{
Datum datum; /* 要被索引的原始數(shù)據(jù) */
Datum leafDatum; /* 要被存儲(chǔ)在葉子中的當(dāng)前數(shù)據(jù) */
int level; /* 當(dāng)前層(從零計(jì)數(shù)) */
/* 來(lái)自當(dāng)前內(nèi)部元組的數(shù)據(jù) */
bool allTheSame; /* tuple is marked all-the-same? */
bool hasPrefix; /* 元組有一個(gè)前綴? */
Datum prefixDatum; /* 如果有,前綴值 */
int nNodes; /* 內(nèi)部元組中的結(jié)點(diǎn)數(shù)目 */
Datum *nodeLabels; /* 結(jié)點(diǎn)標(biāo)簽值(如果沒(méi)有為 NULL) */
} spgChooseIn;
typedef enum spgChooseResultType
{
spgMatchNode = 1, /* 下降到現(xiàn)有結(jié)點(diǎn) */
spgAddNode, /* 向內(nèi)部元組增加一個(gè)結(jié)點(diǎn) */
spgSplitTuple /* 劃分內(nèi)部元組(修改它的前綴) */
} spgChooseResultType;
typedef struct spgChooseOut
{
spgChooseResultType resultType; /* 動(dòng)作代碼,見(jiàn)上文 */
union
{
struct /* 用于spgMatchNode的結(jié)果 */
{
int nodeN; /* 下降到這個(gè)結(jié)點(diǎn)(索引從 0 開(kāi)始) */
int levelAdd; /* 這次匹配增加的層 */
Datum restDatum; /* 新葉數(shù)據(jù) */
} matchNode;
struct /* 用于spgAddNode的結(jié)果 */
{
Datum nodeLabel; /* 新結(jié)點(diǎn)的標(biāo)簽 */
int nodeN; /* 在哪里插入它(索引從 0 開(kāi)始) */
} addNode;
struct /* 用于spgSplitTuple的結(jié)果 */
{
/* 來(lái)自有一個(gè)子元組的新上層內(nèi)部元組的信息 */
bool prefixHasPrefix; /* 元組能有前綴嗎? */
Datum prefixPrefixDatum; /* 如果有,前綴值 */
int prefixNNodes; /* 節(jié)點(diǎn)的數(shù)目 */
Datum *prefixNodeLabels; /* 它們的標(biāo)簽(NULL表示無(wú)標(biāo)簽)*/
int childNodeN; /* 哪個(gè)節(jié)點(diǎn)有子元組 */
/* 來(lái)自放有所有舊結(jié)點(diǎn)的新下層內(nèi)部元組的信息 */
bool postfixHasPrefix; /* 元組能有前綴嗎? */
Datum postfixPrefixDatum; /* 如果有,前綴值 */
} splitTuple;
} result;
} spgChooseOut;
datum
是要被插入到該索引中的spgConfigIn
.attType
類(lèi)型的原始數(shù)據(jù)。leafDatum
是一個(gè)spgConfigOut
.leafType
類(lèi)型的值,它最初是方法
compress
應(yīng)用到datum
上的結(jié)果(如果提供了方法compress
)或者是和datum
相同的值(如果沒(méi)有提供compress
方法)。但是如果choose
或picksplit
改變了它,那么位于樹(shù)的較低層的
leafDatum
值可能會(huì)改變。當(dāng)插入搜索到達(dá)一個(gè)葉子頁(yè),leafDatum
的當(dāng)前值就會(huì)被存儲(chǔ)在新創(chuàng)建的葉子元組中。level
是當(dāng)前內(nèi)部元組的層次,根層是 0 。如果當(dāng)前內(nèi)部元組被標(biāo)記為包含多個(gè)等價(jià)節(jié)點(diǎn)(見(jiàn)第 65.4.3 節(jié)),
allTheSame
為真。如果當(dāng)前內(nèi)部元組有一個(gè)前綴,hasPrefix
為真,如果這樣,prefixDatum
為前綴值。nNodes
是包含在內(nèi)部元組中子結(jié)點(diǎn)的數(shù)量,并且nodeLabels
是這些子結(jié)點(diǎn)的標(biāo)簽值的數(shù)組,如果沒(méi)有標(biāo)簽則為
NULL。
choose
函數(shù)能決定新值是匹配一個(gè)現(xiàn)有子結(jié)點(diǎn),或是必須增加一個(gè)新的子節(jié)點(diǎn),亦或是新值和元組的前綴不一致并且因此該內(nèi)部元組必須被分裂來(lái)創(chuàng)建限制性更低的前綴。
如果新值匹配一個(gè)現(xiàn)有的子結(jié)點(diǎn),將resultType
設(shè)置為spgMatchNode
。將nodeN
設(shè)置為該結(jié)點(diǎn)在結(jié)點(diǎn)數(shù)組中的索引(從零開(kāi)始)。將levelAdd
設(shè)置為傳到該結(jié)點(diǎn)導(dǎo)致的level
增加,或者在操作符類(lèi)不使用層數(shù)時(shí)將它置為零。如果操作符類(lèi)沒(méi)有把數(shù)據(jù)從一層修改到下一層,將
restDatum
設(shè)置為等于datum
,否則將它設(shè)置為在下一層用作leafDatum
的被修改后的值。
如果必須增加一個(gè)新的子結(jié)點(diǎn),將resultType
設(shè)置為spgAddNode
。將nodeLabel
設(shè)置為在新結(jié)點(diǎn)中使用的標(biāo)簽,并將nodeN
設(shè)置為插入該結(jié)點(diǎn)的位置在結(jié)點(diǎn)數(shù)組中的索引(從零開(kāi)始)。在結(jié)點(diǎn)被增加之后,choose
函數(shù)將被再次調(diào)用并使用修改后的內(nèi)部元組,那時(shí)將會(huì)導(dǎo)致一個(gè)
spgMatchNode
結(jié)果。
如果新值和元組的前綴不一致,將resultType
設(shè)置為spgSplitTuple
。這個(gè)動(dòng)作將所有現(xiàn)有的結(jié)點(diǎn)移動(dòng)到一個(gè)新的下層內(nèi)部元組,并且將現(xiàn)有的內(nèi)部元組用一個(gè)新元組替換,該元組只有一個(gè)到那個(gè)新的下層內(nèi)部元組的向下鏈接。將prefixHasPrefix
設(shè)置為指示新的上層元組是否具有一個(gè)前綴,并且在如果有前綴時(shí)設(shè)置
prefixPrefixDatum
為前綴值。這個(gè)新的前綴值必須比原來(lái)的值要足夠?qū)捤梢员隳軌蚪邮軐⒈凰饕男轮?。?code class="structfield">prefixNNodes設(shè)置為新元組中所需的節(jié)點(diǎn)數(shù),并且將prefixNodeLabels
設(shè)置為一個(gè)已分配的保存它們的標(biāo)簽的數(shù)組,或者在不要求節(jié)點(diǎn)標(biāo)簽時(shí)設(shè)置為NULL。注意新上層元組的總尺寸必須不超過(guò)它所替換的元組的總尺寸,這限制了新前綴和新標(biāo)簽的長(zhǎng)度。將
childNodeN
設(shè)置為將下鏈到新的下層內(nèi)元組的節(jié)點(diǎn)的索引(從零開(kāi)始)。設(shè)置postfixHasPrefix
表示新的下層內(nèi)元組是否應(yīng)該有一個(gè)前綴,并且在應(yīng)該有前綴的情況下設(shè)置postfixPrefixDatum
為前綴值。這兩種前綴以及下鏈節(jié)點(diǎn)的標(biāo)簽(如果有)的組合必須具有與原始前綴相同的含義,因?yàn)闆](méi)有機(jī)會(huì)修改被移動(dòng)到新下層元組的節(jié)點(diǎn)標(biāo)簽,也不能更改任何子索引項(xiàng)。在該節(jié)點(diǎn)被分裂后,將再次用替換的內(nèi)元組調(diào)用
choose
函數(shù)。如果spgSplitTuple
動(dòng)作沒(méi)有創(chuàng)建出合適的節(jié)點(diǎn),該調(diào)用可以返回一個(gè)spgAddNode
結(jié)果。最終choose
必須返回spgMatchNode
以允許插入下降到下一層次中。
picksplit
決定如何在一組葉子元組上創(chuàng)建一個(gè)新的內(nèi)部元組。
該函數(shù)的SQL聲明必須看起來(lái)像這樣:
CREATE FUNCTION my_picksplit(internal, internal) RETURNS void ...
第一個(gè)參數(shù)是一個(gè)指向spgPickSplitIn
C 結(jié)構(gòu)的指針,包含該函數(shù)的輸入數(shù)據(jù)。第二個(gè)參數(shù)是一個(gè)指向spgPickSplitOut
C 結(jié)構(gòu)的指針,函數(shù)必須將結(jié)果數(shù)據(jù)填充在其中。
typedef struct spgPickSplitIn
{
int nTuples; /* 葉子元組的數(shù)量 */
Datum *datums; /* 它們的數(shù)據(jù)(長(zhǎng)度為 nTuples 的數(shù)組) */
int level; /* 當(dāng)前層次(從零開(kāi)始計(jì)) */
} spgPickSplitIn;
typedef struct spgPickSplitOut
{
bool hasPrefix; /* 新內(nèi)部元組應(yīng)該有一個(gè)前綴嗎? */
Datum prefixDatum; /* 如果有,前綴值 */
int nNodes; /* 新內(nèi)部元組的結(jié)點(diǎn)數(shù) */
Datum *nodeLabels; /* 它們的標(biāo)簽(沒(méi)有標(biāo)簽則為NULL) */
int *mapTuplesToNodes; /* 每一個(gè)葉子元組的結(jié)點(diǎn)索引 */
Datum *leafTupleDatums; /* 存儲(chǔ)在每一個(gè)新葉子元組中的數(shù)據(jù) */
} spgPickSplitOut;
nTuples
是提供的葉子元組的數(shù)目。datums
是它們的spgConfigOut
.leafType
類(lèi)型的數(shù)據(jù)值的數(shù)組。level
是所有這些葉子元組共享的當(dāng)前層,它將成為新內(nèi)部元組所在的層次。
將hasPrefix
設(shè)置為指示新內(nèi)部元組是否應(yīng)該有前綴,并且如果有前綴則將prefixDatum
設(shè)置成前綴值。將nNodes
設(shè)置為新內(nèi)部元組將包含的結(jié)點(diǎn)數(shù)目,并且將nodeLabels
設(shè)置為它們的標(biāo)簽值的數(shù)組或者 NULL(如果結(jié)點(diǎn)不要求標(biāo)簽)。將
mapTuplesToNodes
設(shè)置為一個(gè)數(shù)組,該數(shù)組告訴每一個(gè)葉子元組應(yīng)該被賦予的結(jié)點(diǎn)的索引(從零開(kāi)始)。將leafTupleDatums
設(shè)置為由將要被存儲(chǔ)在新葉子元組中的值構(gòu)成的一個(gè)數(shù)組(如果操作符類(lèi)不將數(shù)據(jù)從一層修改到下一層,這些值將和輸入的datums
相同)。注意picksplit
函數(shù)負(fù)責(zé)為
nodeLabels
、mapTuplesToNodes
和leafTupleDatums
數(shù)組進(jìn)行 palloc。
如果提供了多于一個(gè)葉子元組,picksplit
被寄望于將它們分類(lèi)到多余一個(gè)結(jié)點(diǎn)中;否則不可能將葉子元組劃分到多個(gè)頁(yè)面,這也是這個(gè)操作的終極目的。因此,如果picksplit
函數(shù)結(jié)束時(shí)把所有葉子元組放在同一個(gè)結(jié)點(diǎn)中,核心SP-GiST代碼將覆蓋該決定,并且生成一個(gè)內(nèi)部元組,將葉子元組隨機(jī)分配到多個(gè)不同標(biāo)簽的結(jié)點(diǎn)。這樣一個(gè)元組被標(biāo)記為allTheSame
來(lái)表示發(fā)生了這種情況。
choose
和inner_consistent
函數(shù)必須對(duì)這樣的內(nèi)部元組采取合適的處理。詳見(jiàn)第 65.4.3 節(jié)。
picksplit
只能在一種情況下被應(yīng)用在單獨(dú)一個(gè)葉子元組上,這種情況是config
函數(shù)將longValuesOK
設(shè)置為真并且提供了一個(gè)長(zhǎng)于一頁(yè)的輸入。在這種情況中,該操作的要點(diǎn)是剝離一個(gè)前綴并且產(chǎn)生一個(gè)新的、較短的葉子數(shù)據(jù)值。這種調(diào)用將被重復(fù)直到產(chǎn)生一個(gè)足夠短能夠放入到一頁(yè)的葉子數(shù)據(jù)。詳見(jiàn)第 65.4.1 節(jié)。
inner_consistent
在樹(shù)搜索過(guò)程中返回一組要追求的結(jié)點(diǎn)(分支)。
該函數(shù)的SQL聲明必須看起來(lái)像這樣:
CREATE FUNCTION my_inner_consistent(internal, internal) RETURNS void ...
第一個(gè)參數(shù)是一個(gè)指向spgInnerConsistentIn
C 結(jié)構(gòu)的指針,包含該函數(shù)的輸入數(shù)據(jù)。第二個(gè)參數(shù)是一個(gè)指向spgInnerConsistentOut
C 結(jié)構(gòu)的指針,函數(shù)必須將結(jié)果數(shù)據(jù)填充在其中。
typedef struct spgInnerConsistentIn
{
ScanKey scankeys; /* 操作符和比較值的數(shù)組 */
ScanKey orderbys; /* 排序運(yùn)算符和比較數(shù)組
* 值 */
int nkeys; /* 掃描鍵數(shù)組的長(zhǎng)度 */
int norderbys; /* 排序數(shù)組的長(zhǎng)度 */
Datum reconstructedValue; /* 在父結(jié)點(diǎn)中的重構(gòu)值 */
void *traversalValue; /* 操作符類(lèi)相關(guān)的貫穿值 */
MemoryContext traversalMemoryContext; /* 把新的貫穿值放在這里 */
int level; /* 當(dāng)前層次(從零開(kāi)始計(jì)) */
bool returnData; /* 是否必須返回原始數(shù)據(jù)? */
/* 來(lái)自當(dāng)前內(nèi)元組的數(shù)據(jù) */
bool allTheSame; /* 元組被標(biāo)記為完全相同? */
bool hasPrefix; /* 元組有前綴? */
Datum prefixDatum; /* 如果有,前綴值 */
int nNodes; /* 內(nèi)元組中的結(jié)點(diǎn)數(shù) */
Datum *nodeLabels; /* 結(jié)點(diǎn)標(biāo)簽值(沒(méi)有就是 NULL) */
} spgInnerConsistentIn;
typedef struct spgInnerConsistentOut
{
int nNodes; /* 要被訪問(wèn)的子結(jié)點(diǎn)數(shù) */
int *nodeNumbers; /* 它們?cè)诮Y(jié)點(diǎn)數(shù)組中的索引 */
int *levelAdds; /* 為每個(gè)子結(jié)點(diǎn)要增加的層數(shù) */
Datum *reconstructedValues; /* 相關(guān)的重構(gòu)值 */
void **traversalValues; /* 操作符類(lèi)相關(guān)的貫穿值 */
double **distances; /* 關(guān)聯(lián)距離 */
} spgInnerConsistentOut;
長(zhǎng)度為nkeys
的數(shù)組scankeys
描述了索引搜索條件。這些條件用 AND 組合 — 只對(duì)滿足所有條件的索引項(xiàng)感興趣(注意,nkeys
= 0 表示所有索引項(xiàng)滿足該查詢(xún))。通常一致函數(shù)只關(guān)心每個(gè)數(shù)組項(xiàng)的sk_strategy
和
sk_argument
,它們分別給出了可索引操作符和比較值。特別要說(shuō)明的是,沒(méi)有必要去檢查sk_flags
來(lái)看比較值是否為 NULL,因?yàn)?SP-GiST 的核心代碼會(huì)過(guò)濾這樣的條件。 數(shù)組orderbys
,長(zhǎng)度norderbys
,以相同的方式描述排序運(yùn)算符(如果有)。 reconstructedValue
是用于父元組的重構(gòu)值,在根層時(shí)或者如果
inner_consistent
函數(shù)沒(méi)有在父層提供一個(gè)值時(shí),它為(Datum) 0
。reconstructedValue
總是spgConfigOut
.leafType
類(lèi)型。traversalValue
是任意貫穿數(shù)據(jù)的指針,該數(shù)據(jù)由父索引元組上的上一次
inner_consistent
調(diào)用傳遞下來(lái),在根層上這個(gè)指針為 NULL。traversalMemoryContext
是用于存放輸出的貫穿值(見(jiàn)下文)的內(nèi)存上下文。level
是當(dāng)前內(nèi)元組層次,根層是 0。如果這個(gè)查詢(xún)要求重構(gòu)的數(shù)據(jù),returnData
是true
。如果
config
斷言canReturnData
,returnData
只會(huì)是true
。如果當(dāng)前的內(nèi)元組被標(biāo)記為“完全一樣”,那么allTheSame
為真。在這種情況下,所有的結(jié)點(diǎn)都具有相同的標(biāo)簽(如果有),而且它們要么全部匹配該查詢(xún),要么一個(gè)都不匹配查詢(xún)(見(jiàn)
第 65.4.3 節(jié))。如果當(dāng)前內(nèi)元組包含一個(gè)前綴,則hasPrefix
為真。如果這樣,prefixDatum
就是該前綴的值。nNodes
是包含在內(nèi)元組中的子結(jié)點(diǎn)的數(shù)量,nodeLabels
是它們的標(biāo)簽值的數(shù)組。當(dāng)然如果結(jié)點(diǎn)沒(méi)有標(biāo)簽,這個(gè)數(shù)組就為
NULL。
nNodes
必須被設(shè)置為搜索需要訪問(wèn)的子結(jié)點(diǎn)數(shù),并且nodeNumbers
必須被設(shè)置為子結(jié)點(diǎn)索引的數(shù)組。如果操作符類(lèi)跟蹤層次,把levelAdds
設(shè)置成一個(gè)數(shù)組,其中說(shuō)明了在下降到要被訪問(wèn)的每一個(gè)結(jié)點(diǎn)時(shí)需要增加的層數(shù)(通常這些增量對(duì)于所有結(jié)點(diǎn)都是相同的,但是并不一定如此,所以需要使用一個(gè)數(shù)組)。如果需要值重構(gòu),將
reconstructedValues
設(shè)置為一個(gè)spgConfigOut
.leafType
類(lèi)型值的數(shù)組,這些值是為要被訪問(wèn)的每一個(gè)子節(jié)點(diǎn)構(gòu)造的。否則,把reconstructedValues
留為NULL。 如果執(zhí)行有序搜索,根據(jù)orderbys
數(shù)組,設(shè)置
distances
為距離值數(shù)組。(距離最短的節(jié)點(diǎn)將首先處理)。 否則,保留它為空。 如果想要把額外的帶外信息(“貫穿值”)向下傳遞給樹(shù)搜索的較低層,可以把traversalValues
設(shè)置成合適的貫穿值的數(shù)組,其中每一個(gè)元素用于一個(gè)要被訪問(wèn)的子節(jié)點(diǎn)。如果不需要傳遞額外的帶外信息,則把traversalValues
設(shè)置為
NULL。注意,inner_consistent
函數(shù)負(fù)責(zé)在當(dāng)前內(nèi)存上下文中分配nodeNumbers
、levelAdds
、distances
、reconstructedValues
和
traversalValues
數(shù)組。不過(guò),任何由traversalValues
數(shù)組指向的輸出貫穿值應(yīng)該在traversalMemoryContext
中分配。每一個(gè)貫穿值必須是一個(gè)單獨(dú)分配的塊(chunk)。
leaf_consistent
如果一個(gè)葉子元組滿足一個(gè)查詢(xún)則返回真。
該函數(shù)的SQL聲明必須看起來(lái)像這樣:
CREATE FUNCTION my_leaf_consistent(internal, internal) RETURNS bool ...
第一個(gè)參數(shù)是一個(gè)指向spgLeafConsistentIn
C 結(jié)構(gòu)的指針,包含該函數(shù)的輸入數(shù)據(jù)。第二個(gè)參數(shù)是一個(gè)指向spgLeafConsistentOut
C 結(jié)構(gòu)的指針,函數(shù)必須將結(jié)果數(shù)據(jù)填充在其中。
typedef struct spgLeafConsistentIn
{
ScanKey scankeys; /* 操作符和比較值的數(shù)組 */
ScanKey orderbys; /* 排序運(yùn)算符和比較數(shù)組
* 值 */
int nkeys; /* 掃描鍵數(shù)組的長(zhǎng)度 */
int norderbys; /* 排序數(shù)組的長(zhǎng)度 */
Datum reconstructedValue; /* 在父節(jié)點(diǎn)重構(gòu)的值 */
void *traversalValue; /* 操作符類(lèi)相關(guān)的貫穿值 */
int level; /* 當(dāng)前層次(從零開(kāi)始計(jì)) */
bool returnData; /* 是否必須返回原始數(shù)據(jù)? */
Datum leafDatum; /* 葉子元組中的數(shù)據(jù) */
} spgLeafConsistentIn;
typedef struct spgLeafConsistentOut
{
Datum leafValue; /* 重構(gòu)的原始數(shù)據(jù),如果有 */
bool recheck; /* 如果操作符必須被重新檢查則設(shè)為真 */
bool recheckDistances; /* 如果距離必須被重新檢查,設(shè)置為 true */
double *distances; /* 關(guān)聯(lián)距離 */
} spgLeafConsistentOut;
長(zhǎng)度為nkeys
的數(shù)組scankeys
描述了索引搜索條件。這些條件用 AND 組合在一起 — 只有滿足所有條件的索引項(xiàng)才滿足該查詢(xún)(注意nkeys
= 0 表示所有的索引項(xiàng)都滿足查詢(xún))。通常 consistent 函數(shù)值關(guān)注每一個(gè)數(shù)組項(xiàng)的sk_strategy
和
sk_argument
域,它們分別給出了可索引操作符和比較值。特別是它無(wú)需檢查sk_flags
來(lái)檢查比較值是否為 NULL,因?yàn)?SP-GiST 核心代碼將過(guò)濾掉這類(lèi)條件。 數(shù)組orderbys
,長(zhǎng)度norderbys
,以相同的方式描述排序運(yùn)算符(如果有)。 reconstructedValue
是為父元組重構(gòu)的值,在根層或者當(dāng)
inner_consistent
沒(méi)有提供父層上的值時(shí),它是(Datum) 0
。reconstructedValue
總是spgConfigOut
.leafType
類(lèi)型。traversalValue
是任意貫穿數(shù)據(jù)的指針,該數(shù)據(jù)由父索引元組上的上一次
inner_consistent
調(diào)用傳遞下來(lái),在根層上這個(gè)指針為 NULL。level
是當(dāng)前的葉子元組所在的層次,根層為零。如果這個(gè)查詢(xún)要求重構(gòu)的數(shù)據(jù),則returnData
為true
。只有在config
函數(shù)主張了canReturnData
時(shí)才會(huì)如此。
leafDatum
是存儲(chǔ)在當(dāng)前葉子元組中的spgConfigOut
.leafType
的鍵值。
如果葉子元組匹配查詢(xún),則該函數(shù)必須返回true
,否則返回false
。在返回true
的情況中,如果returnData
為true
,則leafValue
必須被設(shè)置為最初為構(gòu)建這個(gè)葉子元組提供的
spgConfigIn
.attType
類(lèi)型值。還有,如果匹配是不確定的并且操作符必須被重新應(yīng)用在實(shí)際堆元組上驗(yàn)證匹配,則recheck
會(huì)被設(shè)置為true
。 如果執(zhí)行有序搜索,則根據(jù)orderbys
數(shù)組設(shè)置distances
為距離值數(shù)組。否則,保留它為空。
如果至少有一個(gè)返回的距離不準(zhǔn)確,則recheckDistances
為 true。 在這種情況下,執(zhí)行器將從堆中獲取元組之后計(jì)算精確的距離,并根據(jù)需要重新排序元組。
可選的用戶定義的方法是:
Datum compress(Datum in)
將數(shù)據(jù)項(xiàng)轉(zhuǎn)換成一種適合索引頁(yè)面的葉子元組中物理存儲(chǔ)方式的格式。它接受spgConfigIn
.attType
值并且返回spgConfigOut
.leafType
值。輸出值不應(yīng)該被TOAST。
options
定義一組控制運(yùn)算符類(lèi)行為的用戶可見(jiàn)參數(shù)。
函數(shù)的 SQL 聲明必須如下所示:
CREATE OR REPLACE FUNCTION my_options(internal)
RETURNS void
AS 'MODULE_PATHNAME'
LANGUAGE C STRICT;
該函數(shù)被傳遞一個(gè)指向 local_relopts
結(jié)構(gòu)的指針,該結(jié)構(gòu)需要填充一組特定于運(yùn)算符類(lèi)的選項(xiàng)。 可以使用 PG_HAS_OPCLASS_OPTIONS()
和 PG_GET_OPCLASS_OPTIONS()
宏從其他支持函數(shù)訪問(wèn)這些選項(xiàng)。
由于 SP-GiST 中鍵的表示是靈活的,它可能取決于用戶指定的參數(shù)。
所有的 SP-GiST 支持方法通常都在一個(gè)短期存在的內(nèi)存上下文中被調(diào)用,即在處理完每一個(gè)元組后CurrentMemoryContext
將被重置。因此并不需要操心 pfree 你 palloc 的任何東西(config
方法是一個(gè)特例:它應(yīng)該避免泄漏內(nèi)存。但是通常config
方法只需要為傳出的參數(shù)結(jié)構(gòu)賦常數(shù)值)。
如果被索引的列是一種可排序的數(shù)據(jù)類(lèi)型,索引的排序規(guī)則將被使用標(biāo)準(zhǔn)的PG_GET_COLLATION()
機(jī)制傳遞給所有的支持方法。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: