我正在阅读 this guide和 this guide更好地了解 postgres 内部是如何工作的,而且大多数事情都是有意义的。但是,我有一个关于并发更新将如何影响 ctid
的问题。链。
据我了解,ctid
s 指向“下一个”(页面,指针)组合来描述给定行的修订。但是,当两个并发事务正在执行并尝试更新同一行时会发生什么?事务具有由它们的 txid 强加的排序,但这并不能保证它们尝试更改行的顺序。这些更新的可能结果是什么?
例如,如果我们有一张表 t
单列 s
如第二个指南和 一 更新,我们可能有:
=> BEGIN;
=> UPDATE t SET s = 'BAR';
=> SELECT txid_current();
txid_current
--------------
3666
=> SELECT * FROM t;
id | s
----+-----
1 | BAR
(1 row)
当我们使用 heap_page
查看页面内部结构的函数,它看起来像:=> SELECT * FROM heap_page('t',0);
ctid | state | xmin | xmax | t_ctid
-------+--------+----------+-------+--------
(0,1) | normal | 3664 (c) | 3666 | (0,2)
(0,2) | normal | 3666 | 0 (a) | (0,2)
如 两个更新同时发生,最终表状态如何随更新:劳伦兹是正确的。关于如何执行更新的证实伪代码,来自链接指南之一的后面,是:
(1) FOR each row that will be updated by this UPDATE command
(2) WHILE true
/* The First Block */
(3) IF the target row is being updated THEN
(4) WAIT for the termination of the transaction that updated the target row
(5) IF (the status of the terminated transaction is COMMITTED)
AND (the isolation level of this transaction is REPEATABLE READ or SERIALIZABLE) THEN
(6) ABORT this transaction /* First-Updater-Win */
ELSE
(7) GOTO step (2)
END IF
/* The Second Block */
(8) ELSE IF the target row has been updated by another concurrent transaction THEN
(9) IF (the isolation level of this transaction is READ COMMITTED THEN
(10) UPDATE the target row
ELSE
(11) ABORT this transaction /* First-Updater-Win */
END IF
/* The Third Block */
ELSE /* The target row is not yet modified or has been updated by a terminated transaction. */
(12) UPDATE the target row
END IF
END WHILE
END FOR
注意第 4 行,它描述了在另一个事务中设置 xmax 的行锁定效果。
最佳答案
答案比你想象的要简单:行锁防止同一行的并发修改,所以问题永远不会出现,更新链不会 fork 。
关于postgresql - Postgres 中的 ctid 链是否在行的并发更新下 fork ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67052991/