W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
FDW回調(diào)函數(shù)GetForeignRelSize
、GetForeignPaths
、GetForeignPlan
、PlanForeignModify
、GetForeignJoinPaths
、
GetForeignUpperPaths
以及PlanDirectModify
必須適合PostgreSQL規(guī)劃器的工作。這里有一些關(guān)于它們必須做什么的注記。
root
和baserel
中的信息可以被用來(lái)減少必須從外部表獲得的信息量(并且因此降低代價(jià))。baserel->baserestrictinfo
是特別有趣的,因?yàn)樗拗茥l件(WHERE
)子句,它應(yīng)該被用來(lái)過(guò)濾要被獲取的行(FDW本身并不要求強(qiáng)制這些條件,因?yàn)楹诵膱?zhí)行器可以檢查它們)。
baserel->reltarget->exprs
可以被用來(lái)決定哪些類需要被獲??;但是注意它僅列出了ForeignScan
計(jì)劃節(jié)點(diǎn)所發(fā)出的列,不包含在條件計(jì)算中使用但并不被查詢輸出的列。
有多個(gè)私有域可以給FDW規(guī)劃函數(shù)來(lái)保存信息。通常,不管你存儲(chǔ)什么在FDW私有域中,它們都應(yīng)該被palloc,這樣它會(huì)在規(guī)劃結(jié)束時(shí)被回收。
baserel->fdw_private
是一個(gè)void
指針,它可以被FDW規(guī)劃函數(shù)用來(lái)存儲(chǔ)與特定外部表相關(guān)的信息。核心規(guī)劃器不會(huì)碰它除非當(dāng)RelOptInfo
節(jié)點(diǎn)被創(chuàng)建時(shí)把它初始化為NULL。它對(duì)從GetForeignRelSize
傳遞信息給GetForeignPaths
和/或從
GetForeignPaths
傳遞信息給GetForeignPlan
非常有用,這樣避免了重新計(jì)算。
GetForeignPaths
可以通過(guò)在ForeignPath
節(jié)點(diǎn)的fdw_private
域中存儲(chǔ)私有信息來(lái)標(biāo)識(shí)不同的訪問(wèn)路徑。fdw_private
被聲明為一個(gè)List
指針,但是可能實(shí)際上包含任何東西,因?yàn)橐?guī)劃器不會(huì)觸碰它。但是,最好是使用一種
nodeToString
可導(dǎo)出的形式,這樣在后端可以用于調(diào)試支持。
GetForeignPlan
可以檢查選中的ForeignPath
節(jié)點(diǎn)的fdw_private
域,并且可以生成被放置于ForeignPath
計(jì)劃節(jié)點(diǎn)中的fdw_exprs
和
fdw_private
列表。這兩個(gè)列表必須被表示為一種copyObject
可復(fù)制的形式。fdw_private
列表沒(méi)有任何其他限制并且不會(huì)被核心后端以任何形式解釋。非 NIL 的fdw_exprs
應(yīng)該包含表達(dá)式樹(shù),該樹(shù)會(huì)在運(yùn)行時(shí)被執(zhí)行。這些樹(shù)將由規(guī)劃器在后期處理,以便讓它們變成完全可執(zhí)行的。
在GetForeignPlan
中,通常被傳入的目標(biāo)列表可以被照樣復(fù)制到計(jì)劃節(jié)點(diǎn)中。被傳入的scan_clauses
列表包含和baserel->baserestrictinfo
相同的子句,但是可能為了更好的執(zhí)行效率會(huì)被重新排序。在簡(jiǎn)單情況下,F(xiàn)DW可以只把RestrictInfo
節(jié)點(diǎn)從
scan_clauses
列表剝離(使用extract_actual_clauses
)并且把所有子句放到計(jì)劃節(jié)點(diǎn)的條件列表中,這意味著所有子句將在運(yùn)行時(shí)由執(zhí)行器檢查。更復(fù)雜的FDW可能可以在內(nèi)部檢查某些子句,著這種情況下哪些子句可以從計(jì)劃節(jié)點(diǎn)的條件列表中刪除,這樣執(zhí)行器就不用浪費(fèi)時(shí)間去檢查它們。
作為一個(gè)例子,F(xiàn)DW可以標(biāo)識(shí)某些foreign_variable
=
sub_expression
形式的限制子句,它決定哪些可以使用由sub_expression
給出的本地計(jì)算值在遠(yuǎn)程服務(wù)器上被執(zhí)行。這樣一個(gè)子句的實(shí)際標(biāo)識(shí)應(yīng)該在
GetForeignPaths
期間發(fā)生,因?yàn)樗赡軙?huì)影響路徑的代價(jià)估計(jì)。路徑的fdw_private
域可能包括一個(gè)已標(biāo)識(shí)的子句的RestrictInfo
節(jié)點(diǎn)。然后GetForeignPlan
將從scan_clauses
中移除該子句,但是將
sub_expression
加到fdw_exprs
來(lái)保證它被揉成可執(zhí)行的形式。它可能還將把控制信息放入到計(jì)劃節(jié)點(diǎn)的fdw_private
域來(lái)告訴執(zhí)行函數(shù)在運(yùn)行時(shí)要做什么。傳遞給遠(yuǎn)程服務(wù)器的查詢將涉及類似WHERE
的東西,使用在運(yùn)行時(shí)從foreign_variable
= $1fdw_exprs
表達(dá)式樹(shù)獲得的參數(shù)值。
任何從該計(jì)劃節(jié)點(diǎn)的條件列表移除的子句必須被加入到fdw_recheck_quals
或者由RecheckForeignScan
重新檢查以便確保在READ COMMITTED
隔離級(jí)別的正確行為。當(dāng)查詢中涉及的某個(gè)其他表上發(fā)生并發(fā)更新時(shí),執(zhí)行器可能需要驗(yàn)證原來(lái)的所有條件仍然對(duì)該元組滿足(可能用一組不同的參數(shù)值)。使用fdw_recheck_quals
通常比在
RecheckForeignScan
中實(shí)現(xiàn)檢查要更容易,但是這種方法不足以應(yīng)付外連接被下推的情況,因?yàn)槟欠N情況下的連接元組可能會(huì)有一些域具有 NULL 但是不會(huì)導(dǎo)致整個(gè)元組被拒絕。
另一個(gè)可以由 FDW 填充的ForeignScan
域是fdw_scan_tlist
,它描述 FDW 為這個(gè)計(jì)劃節(jié)點(diǎn)返回的元組。對(duì)于簡(jiǎn)單的外部表掃描這可以設(shè)置為NIL
,表示返回的元組具有為外部表聲明的行類型。非-NIL
值必須是一個(gè)包含表示返回列的 Var 或表達(dá)式的目標(biāo)列表(
TargetEntry
的列表)。例如,這可以被用來(lái)顯示 FDW 省略了某些查詢不需要的列。還有,如果 FDW 計(jì)算表達(dá)式比在本地計(jì)算代價(jià)更低,可以把那些表達(dá)式加入到fdw_scan_tlist
。注意連接計(jì)劃(從GetForeignJoinPaths
創(chuàng)建的路徑得到)必須總是提供fdw_scan_tlist
來(lái)描述它們將返回的列集合。
FDW應(yīng)該總是只依靠表的限制子句構(gòu)建至少一個(gè)路徑。在連接查詢中,它可能還會(huì)選擇依靠連接子句構(gòu)建路徑,例如foreign_variable
=
local_variable
。這樣的子句將不會(huì)在baserel->baserestrictinfo
中找到,但是必須出現(xiàn)在關(guān)系的連接列表中。使用這樣一個(gè)子句的路徑被稱為一個(gè)
“參數(shù)化路徑”。它必須用一個(gè)合適的param_info
值來(lái)標(biāo)識(shí)其他被使用在選中的連接子句中的關(guān)系;使用get_baserel_parampathinfo
來(lái)計(jì)算該值。在GetForeignPlan
中,連接子句的local_variable
部分將被加到
fdw_exprs
中,并且接著在運(yùn)行時(shí)和一個(gè)普通限制子句一樣工作。
如果一個(gè) FDW 支持遠(yuǎn)程連接,GetForeignJoinPaths
應(yīng)該和GetForeignPaths
對(duì)基本表所作的那樣為潛在的遠(yuǎn)程連接產(chǎn)生ForeignPath
。有關(guān)想要進(jìn)行的連接的信息可以以上述相同的方式傳遞給GetForeignPlan
。不過(guò),
baserestrictinfo
與連接關(guān)系無(wú)關(guān),一個(gè)特定連接的相關(guān)連接子句將被作為一個(gè)獨(dú)立的參數(shù)(extra->restrictlist
)被傳遞給GetForeignJoinPaths
。
FDW 可能會(huì)額外地支持直接執(zhí)行某些在掃描和連接層次之上的計(jì)劃動(dòng)作,例如分組或者聚集。為了提供這類選項(xiàng),F(xiàn)DW 應(yīng)該生成路徑并且把它們插入到合適的上層關(guān)系中。例如,一條表示遠(yuǎn)程聚集的路徑應(yīng)該被使用add_path
插入到UPPERREL_GROUP_AGG
關(guān)系中。這條路徑的代價(jià)將會(huì)與通過(guò)讀取外部關(guān)系的簡(jiǎn)單掃描路徑的本地聚集(注意這樣一條路徑也必須被提供,否則規(guī)劃時(shí)會(huì)有錯(cuò)誤)進(jìn)行比較。如果遠(yuǎn)程聚集路徑勝出(通常是這樣),它會(huì)被以通常的方式(調(diào)用
GetForeignPlan
)轉(zhuǎn)化成計(jì)劃。如果該查詢的所有基本關(guān)系都來(lái)自于同一個(gè) FDW,推薦在GetForeignUpperPaths
回調(diào)函數(shù)中生成這種路徑,該函數(shù)會(huì)為每一個(gè)上層關(guān)系被調(diào)用(即每一次掃描/連接后處理步驟)。
第 56.2.4 節(jié)中描述的PlanForeignModify
以及其他回調(diào)的設(shè)計(jì)是建立在這樣一個(gè)假設(shè)之上:外部表將以通常的方式被掃描并且行更新將被一個(gè)本地ModifyTable
計(jì)劃節(jié)點(diǎn)所驅(qū)動(dòng)。這種方法對(duì)于更新需要讀取本地表以及外部表的一般情況下是必要的。不過(guò),如果操作可以完全由外部服務(wù)器執(zhí)行,F(xiàn)DW
可以產(chǎn)生一個(gè)表示這種操作的計(jì)劃并且把它插入到UPPERREL_FINAL
上層關(guān)系中,在其中它會(huì)與ModifyTable
方法競(jìng)爭(zhēng)。這種方法還可以被用來(lái)實(shí)現(xiàn)遠(yuǎn)程SELECT FOR UPDATE
,而不使用第 56.2.5 節(jié)中描述的行鎖定回調(diào)。記住插入到UPPERREL_FINAL
中的路徑負(fù)責(zé)實(shí)現(xiàn)查詢的所有行為。
在規(guī)劃一個(gè)UPDATE
或DELETE
時(shí),PlanForeignModify
和PlanDirectModify
能為外部表查找RelOptInfo
結(jié)構(gòu),并利用之前由掃描規(guī)劃函數(shù)創(chuàng)建的baserel->fdw_private
數(shù)據(jù)。但是,在
INSERT
中目標(biāo)表不會(huì)被掃描,因此不會(huì)有它的RelOptInfo
。由PlanForeignModify
返回的List
具有和ForeignScan
計(jì)劃節(jié)點(diǎn)的fdw_private
列表相同的限制,即它必須只包含
copyObject
知道怎么拷貝的結(jié)構(gòu)。
帶有一個(gè)ON CONFLICT
子句的INSERT
不支持指定沖突目標(biāo),因?yàn)楸镜夭恢肋h(yuǎn)程表上的唯一約束和排除約束的情況。然后這也意味著ON CONFLICT DO UPDATE
不被支持,因?yàn)樵撜f(shuō)明是強(qiáng)制性的。
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)系方式:
更多建議: