W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
如果一個(gè) FDW 的底層存儲(chǔ)機(jī)制具有鎖定行的概念來(lái)阻止對(duì)行的并發(fā)更新,通常值得 FDW 去執(zhí)行行級(jí)鎖定以盡可能接近在普通PostgreSQL表中所實(shí)際使用的語(yǔ)義。涉及這個(gè)問(wèn)題有多種考慮。
要做出的一個(gè)關(guān)鍵決定是執(zhí)行早期鎖定還是晚期鎖定。在早期鎖定中,當(dāng)一行被第一次從底層存儲(chǔ)中檢索到時(shí),它會(huì)被鎖定;而在晚期鎖定中,只有當(dāng)行需要被鎖定時(shí)才鎖定它(由于某些行可能被本地檢查的限制或者連接條件拋棄,所以會(huì)出現(xiàn)不同)。早期鎖定更加簡(jiǎn)單并且能避免額外地與遠(yuǎn)程存儲(chǔ)交互,但是可能會(huì)導(dǎo)致一些不需要鎖定的行也被鎖定,最終造成并發(fā)性下降甚至意外的死鎖。還有,只有在要被鎖定的行可以在后期唯一地重新標(biāo)識(shí)時(shí)才可以用晚期鎖定。較好的行標(biāo)識(shí)符應(yīng)該能標(biāo)識(shí)行的特定版本,就像 PostgreSQLTID 那樣。
默認(rèn)情況下,PostgreSQL在與 FDW 交互時(shí)會(huì)忽略鎖定考慮,但是 FDW 可以在沒(méi)有核心代碼顯式支持的情況下執(zhí)行早期鎖定。第 56.2.5 節(jié)中描述的 API 函數(shù)(在PostgreSQL 9.5 中加入)允許 FDW 按照意愿使用晚期鎖定。
一個(gè)額外的考慮是在READ COMMITTED
隔離模式中,PostgreSQL可能需要對(duì)某個(gè)目標(biāo)元組的更新版本進(jìn)行限制以及連接條件的重新檢查。重新檢查連接條件要求重新獲得之前連接成目標(biāo)元組的非目標(biāo)行拷貝。在標(biāo)準(zhǔn)PostgreSQL表的情況下,這可以通過(guò)在連接投影出的列列表中包括非目標(biāo)表的 TID 并且在需要時(shí)重新取得非目標(biāo)行來(lái)做到。這種方法可以讓連接數(shù)據(jù)集保持緊湊,但是它要求代價(jià)較低的重新取得元組的功能,還有
TID 要能夠唯一地標(biāo)識(shí)要被重新取得的行版本。因此,默認(rèn)情況下用于外部表的方法是將整個(gè)外部表元組的拷貝包括在從連接投影出的列列表中。這不會(huì)對(duì) FDW 有特殊的要求,但是會(huì)導(dǎo)致歸并和哈希連接性能下降。要滿足重新取得元組需求的 FDW 可以選擇第一種方式。
對(duì)于在外部表上的UPDATE
或者DELETE
,推薦目標(biāo)表上的ForeignScan
操作在它取得的行上執(zhí)行早期鎖定(可能通過(guò)SELECT FOR UPDATE
的等效體)。通過(guò)在規(guī)劃時(shí)比較一個(gè)表的 relid 和root->parse->resultRelation
或在執(zhí)行時(shí)使用
ExecRelationIsTargetRelation()
,一個(gè) FDW 可以檢測(cè)該表是否為UPDATE
/DELETE
的目標(biāo)。另一種可能性是在ExecForeignUpdate
或者ExecForeignDelete
回調(diào)中執(zhí)行晚期鎖定,但是對(duì)此沒(méi)有特別的支持。
對(duì)于通過(guò)SELECT FOR UPDATE/SHARE
命令指定要被鎖定的外部表,ForeignScan
操作同樣可以通過(guò)用SELECT FOR UPDATE/SHARE
的等效體取元組來(lái)執(zhí)行早期鎖定。要執(zhí)行晚期鎖定,請(qǐng)?zhí)峁?a class="xref" href="fdw-callbacks.html#FDW-CALLBACKS-ROW-LOCKING" title="56.2.5. 用于行鎖定的 FDW 例程">第 56.2.5 節(jié)中定義的回調(diào)函數(shù)。在GetForeignRowMarkType
中,根據(jù)請(qǐng)求的鎖長(zhǎng)度來(lái)選擇行標(biāo)記選項(xiàng)ROW_MARK_EXCLUSIVE
、ROW_MARK_NOKEYEXCLUSIVE
、ROW_MARK_SHARE
或者
ROW_MARK_KEYSHARE
(不管選擇哪一種選項(xiàng),核心代碼都會(huì)做同樣的事情)。在別的地方,可以在規(guī)劃時(shí)用get_plan_rowmark
或者在執(zhí)行時(shí)用ExecFindRowMark
來(lái)檢測(cè)一個(gè)外部表是否被指定由這種類型的命令鎖定。你必須不僅僅檢測(cè)是否返回了一個(gè)非空的行標(biāo)記結(jié)構(gòu),還要檢測(cè)它的strength
域不是
LCS_NONE
。
最后,對(duì)于在UPDATE
、DELETE
或者SELECT FOR UPDATE/SHARE
命令中使用但是沒(méi)有被指定要行鎖定的外部表,你可以在看到鎖長(zhǎng)度LCS_NONE
時(shí)通過(guò)使用GetForeignRowMarkType
選擇選項(xiàng)
ROW_MARK_REFERENCE
來(lái)把默認(rèn)選擇覆蓋為拷貝整個(gè)行。 這將導(dǎo)致用那個(gè)值作為markType
來(lái)調(diào)用RefetchForeignRow
。它應(yīng)該接著重新取得該行而不獲取任何新鎖(如果你有一個(gè)GetForeignRowMarkType
函數(shù),但是不想重新取未鎖定的行,可為LCS_NONE
選擇選項(xiàng)
ROW_MARK_COPY
)。
更多信息可見(jiàn)src/include/nodes/lockoptions.h
,以及src/include/nodes/plannodes.h
中RowMarkType
和PlanRowMark
的注釋,還有src/include/nodes/execnodes.h
中
ExecRowMark
的注釋。
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)系方式:
更多建議: