如果 FDW 的底層儲存機制具有鎖定個別資料列的概念,以防止同時更新這些資料列,那麼 FDW 通常值得執行資料列層級鎖定,並盡可能接近普通 PostgreSQL 表格中使用的語意。 這其中涉及多個考量因素。
需要做出的關鍵決定之一是執行早期鎖定還是延遲鎖定。 在早期鎖定中,資料列在首次從底層儲存擷取時被鎖定,而在延遲鎖定中,資料列僅在已知需要鎖定時才被鎖定。(差異產生是因為某些資料列可能被本地檢查的限制或聯接條件丟棄。)早期鎖定更簡單,避免了與遠端儲存進行額外的往返,但它可能導致鎖定不需要鎖定的資料列,從而導致並行性降低甚至意外的死鎖。 此外,只有在稍後可以唯一地重新識別要鎖定的資料列時,才可能進行延遲鎖定。 最好是資料列識別碼應識別資料列的特定版本,如同 PostgreSQL TIDs 一樣。
預設情況下,PostgreSQL 在與 FDW 介接時會忽略鎖定考量因素,但 FDW 可以執行早期鎖定,而無需核心程式碼的任何明確支援。 第 57.2.6 節中描述的 API 函式是在 PostgreSQL 9.5 中新增的,如果 FDW 願意,可以使用延遲鎖定。
另一個考量因素是,在 READ COMMITTED
隔離模式中,PostgreSQL 可能需要針對某些目標元組的更新版本重新檢查限制和聯接條件。 重新檢查聯接條件需要重新取得先前聯接到目標元組的非目標資料列的副本。 在使用標準 PostgreSQL 表格時,這是透過將非目標表格的 TID 包含在透過聯接投影的欄位清單中來完成的,然後在需要時重新擷取非目標資料列。 這種方法使聯接資料集保持緊湊,但它需要低成本的重新擷取功能,以及可以唯一識別要重新擷取的資料列版本的 TID。 因此,預設情況下,與外部表格一起使用的方法是在透過聯接投影的欄位清單中包含從外部表格擷取的整個資料列的副本。 這對 FDW 沒有特殊要求,但可能導致合併和雜湊聯接的效能降低。 能夠滿足重新擷取要求的 FDW 可以選擇第一種方式。
對於外部表格上的 UPDATE
或 DELETE
,建議目標表格上的 ForeignScan
作業對其擷取的資料列執行早期鎖定,可能透過等效於 SELECT FOR UPDATE
的方式。 FDW 可以透過將其 relid 與 root->parse->resultRelation
進行比較,在計畫時間偵測表格是否為 UPDATE
/DELETE
目標,或透過使用 ExecRelationIsTargetRelation()
在執行時間偵測。 另一種可能性是在 ExecForeignUpdate
或 ExecForeignDelete
回呼中執行延遲鎖定,但沒有為此提供特殊支援。
對於指定由 SELECT FOR UPDATE/SHARE
命令鎖定的外部表格,ForeignScan
作業可以再次透過使用等效於 SELECT FOR UPDATE/SHARE
的方式擷取元組來執行早期鎖定。 若要改為執行延遲鎖定,請提供 第 57.2.6 節中定義的回呼函式。 在 GetForeignRowMarkType
中,根據要求的鎖定強度選擇資料列標記選項 ROW_MARK_EXCLUSIVE
、ROW_MARK_NOKEYEXCLUSIVE
、ROW_MARK_SHARE
或 ROW_MARK_KEYSHARE
。(核心程式碼的行為相同,無論您選擇這四個選項中的哪一個。)在其他地方,您可以使用計畫時間的 get_plan_rowmark
或執行時間的 ExecFindRowMark
來偵測是否指定要由此類型的命令鎖定外部表格;您不僅必須檢查是否傳回了非 Null 的資料列標記結構,而且還必須檢查其 strength
欄位是否不是 LCS_NONE
。
最後,對於在 UPDATE
、DELETE
或 SELECT FOR UPDATE/SHARE
命令中使用但未指定要進行資料列鎖定的外部表格,您可以透過讓 GetForeignRowMarkType
在看到鎖定強度 LCS_NONE
時選擇選項 ROW_MARK_REFERENCE
,來覆寫複製整個資料列的預設選項。 這將導致使用 markType
的該值呼叫 RefetchForeignRow
;然後它應該重新擷取資料列,而不取得任何新的鎖定。(如果您有一個 GetForeignRowMarkType
函式,但不希望重新擷取未鎖定的資料列,請針對 LCS_NONE
選擇選項 ROW_MARK_COPY
。)
請參閱 src/include/nodes/lockoptions.h
、src/include/nodes/plannodes.h
中 RowMarkType
和 PlanRowMark
的註解,以及 src/include/nodes/execnodes.h
中 ExecRowMark
的註解,以獲取更多資訊。
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清之處,請使用此表單回報文件問題。