FDW 回撥函式 GetForeignRelSize
、GetForeignPaths
、GetForeignPlan
、PlanForeignModify
、GetForeignJoinPaths
、GetForeignUpperPaths
和 PlanDirectModify
必須能夠融入 PostgreSQL 規劃器的運作中。以下是一些關於它們必須做什麼的說明。
可以使用 root
和 baserel
中的資訊來減少必須從外部表中獲取的資訊量(從而降低成本)。baserel->baserestrictinfo
尤其有趣,因為它包含應該用於過濾要獲取的行的限制條件(WHERE
子句)。(FDW 本身不需要強制執行這些條件,因為核心執行器可以改為檢查它們。)baserel->reltarget->exprs
可用於確定需要獲取哪些列;但請注意,它僅列出必須由 ForeignScan
計劃節點發出的列,而不包括在條件評估中使用但未由查詢輸出的列。
各種私有欄位可供 FDW 規劃函式用於保留資訊。通常,您在 FDW 私有欄位中儲存的任何內容都應該被 palloc'd,以便在規劃結束時被回收。
baserel->fdw_private
是一個 void
指標,可供 FDW 規劃函式儲存與特定外部表相關的資訊。核心規劃器除了在建立 RelOptInfo
節點時將其初始化為 NULL 外,不會觸及它。它對於將資訊從 GetForeignRelSize
傳遞到 GetForeignPaths
和/或從 GetForeignPaths
傳遞到 GetForeignPlan
非常有用,從而避免重新計算。
GetForeignPaths
可以透過在 ForeignPath
節點的 fdw_private
欄位中儲存私有資訊來識別不同訪問路徑的含義。fdw_private
被宣告為一個 List
指標,但實際上可以包含任何內容,因為核心規劃器不會觸及它。但是,最佳實踐是使用一個可由 nodeToString
轉儲的表示形式,以便與後端中可用的除錯支援一起使用。
GetForeignPlan
可以檢查選定的 ForeignPath
節點的 fdw_private
欄位,並可以生成 fdw_exprs
和 fdw_private
列表,將它們放入 ForeignScan
計劃節點,在那裡它們將在執行時可用。這兩個列表都必須以 copyObject
知道如何複製的形式表示。fdw_private
列表沒有其他限制,並且不會被核心後端以任何方式解釋。fdw_exprs
列表(如果不是 NIL)應包含打算在執行時執行的表示式樹。這些樹將經過規劃器的後處理,使其完全可執行。
在 GetForeignPlan
中,通常可以將傳入的目標列表原樣複製到計劃節點中。傳入的 scan_clauses
列表包含與 baserel->baserestrictinfo
相同的子句,但可能會重新排序以提高執行效率。在簡單的情況下,FDW 可以直接從 scan_clauses
列表(使用 extract_actual_clauses
)中剝離 RestrictInfo
節點,並將所有子句放入計劃節點的 qual 列表中,這意味著所有子句將在執行時由執行器檢查。更復雜的 FDW 可能能夠內部檢查其中一些子句,在這種情況下,可以從計劃節點的 qual 列表中刪除這些子句,以避免執行器浪費時間重新檢查它們。
例如,FDW 可能會識別一些形式為 foreign_variable
=
sub_expression
的限制子句,它確定在給定本地評估的 sub_expression
值的情況下,可以在遠端伺服器上執行這些子句。對此類子句的實際識別應該在 GetForeignPaths
期間發生,因為它會影響路徑的成本估計。路徑的 fdw_private
欄位可能包括指向已識別子句的 RestrictInfo
節點的指標。然後 GetForeignPlan
將該子句從 scan_clauses
中刪除,但將 sub_expression
新增到 fdw_exprs
中,以確保它被處理成可執行的形式。它可能還會將控制資訊放入計劃節點的 fdw_private
欄位,以告知執行函式在執行時做什麼。傳送到遠端伺服器的查詢將涉及類似 WHERE
的內容,其中引數值將在執行時從 foreign_variable
= $1fdw_exprs
表示式樹的評估中獲得。
從計劃節點 qual 列表中刪除的任何子句必須改而新增到 fdw_recheck_quals
中,或由 RecheckForeignScan
重新檢查,以確保在 READ COMMITTED
隔離級別下的正確行為。當查詢涉及的另一個表發生併發更新時,執行器可能需要驗證原始子句是否仍然滿足該元組,可能針對一組不同的引數值。使用 fdw_recheck_quals
通常比在 RecheckForeignScan
中實現檢查更容易,但當外部連線被下推時,此方法將不足夠,因為在這種情況下,連線元組的某些欄位可能變為 NULL 而不完全拒絕該元組。
FDW 可以填充的另一個 ForeignScan
欄位是 fdw_scan_tlist
,它描述了 FDW 為該計劃節點返回的元組。對於簡單的外部表掃描,這可以設定為 NIL
,這意味著返回的元組具有為外部表宣告的行型別。非 NIL
值必須是一個目標列表(TargetEntry
s 的列表),包含代表返回列的 Vars 和/或表示式。這可以用於,例如,表明 FDW 已省略了它注意到查詢不需要的某些列。另外,如果 FDW 可以比本地更便宜地計算查詢使用的表示式,它可以將這些表示式新增到 fdw_scan_tlist
。請注意,連線計劃(由 GetForeignJoinPaths
建立的路徑生成)必須始終提供 fdw_scan_tlist
來描述它們將返回的列集。
FDW 應始終構造至少一個僅依賴於表限制子句的路徑。在連線查詢中,它還可以選擇構造依賴於連線子句的路徑,例如 foreign_variable
=
local_variable
。此類子句不會出現在 baserel->baserestrictinfo
中,但必須在關係的連線列表中查詢。使用此類子句的路徑稱為“引數化路徑”。它必須使用 param_info
的適當值來識別選定連線子句中使用的其他關係;使用 get_baserel_parampathinfo
來計算該值。在 GetForeignPlan
中,連線子句的 local_variable
部分將被新增到 fdw_exprs
中,然後在執行時,該情況與普通限制子句的情況相同。
如果 FDW 支援遠端連線,GetForeignJoinPaths
應該以與 GetForeignPaths
對基本表的操作方式類似的方式為潛在的遠端連線生成 ForeignPath
。有關預期連線的資訊可以像上面描述的那樣傳遞給 GetForeignPlan
。但是,baserestrictinfo
對於連線關係無關緊要;相反,特定連線的相關連線子句作為單獨的引數(extra->restrictlist
)傳遞給 GetForeignJoinPaths
。
FDW 可能還支援對掃描和連線級別之上的某些計劃操作的直接執行,例如分組或聚合。為了提供此類選項,FDW 應生成路徑並將其插入到適當的上層關係中。例如,代表遠端聚合的路徑應使用 add_path
插入到 UPPERREL_GROUP_AGG
關係中。這條路徑將在成本基礎上與透過讀取外部關係(請注意,必須也提供這樣的路徑,否則計劃時會出錯)的簡單掃描路徑進行的本地聚合進行比較。如果遠端聚合路徑獲勝(通常情況如此),它將透過呼叫 GetForeignPlan
以通常的方式轉換為計劃。建議的生成此類路徑的位置是在 GetForeignUpperPaths
回撥函式中,該函式在每個上層關係(即每個掃描/連線後處理步驟)被呼叫,前提是查詢的所有基本關係都來自同一個 FDW。
PlanForeignModify
和 58.2.4 節中描述的其他回撥函式的設計假設外部關係將以常規方式進行掃描,然後將單個行更新由本地 ModifyTable
計劃節點驅動。這種方法對於需要讀取本地表和外部表的一般情況是必要的。但是,如果操作可以完全由外部伺服器執行,FDW 可以生成代表該操作的路徑並將其插入到 UPPERREL_FINAL
上層關係中,在那裡它將與 ModifyTable
方法競爭。這種方法也可以用於實現遠端 SELECT FOR UPDATE
,而不是使用 58.2.6 節中描述的行鎖定回撥。請記住,插入到 UPPERREL_FINAL
的路徑負責實現查詢的所有行為。
在規劃 UPDATE
或 DELETE
時,PlanForeignModify
和 PlanDirectModify
可以查詢外部表的 RelOptInfo
結構,並利用掃描規劃函式之前建立的 baserel->fdw_private
資料。但是,在 INSERT
中,目標表不會被掃描,因此沒有它的 RelOptInfo
。PlanForeignModify
返回的 List
與 ForeignScan
計劃節點的 fdw_private
列表具有相同的限制,即它只能包含 copyObject
知道如何複製的結構。
INSERT
語句加上 ON CONFLICT
子句不支援指定衝突目標,因為遠端表上的唯一約束或排除約束在本地是未知的。這反過來也意味著 ON CONFLICT DO UPDATE
不被支援,因為在那裡必須指定衝突目標。
如果您在文件中發現任何不正確之處、與您使用該特定功能時的經驗不符之處或需要進一步澄清之處,請使用 此表單 來報告文件問題。