Postgres中的ctid链是否在并发更新一行的情况下分叉



我阅读本指南和本指南是为了更好地了解postgres内部是如何工作的,而且大多数事情都是有意义的。但是,我有一个问题,即并发更新将如何影响ctid链。

正如我所理解的,CCD_;下一个";(页面,指针(组合框,用于描述对给定行的修订。然而,当两个并发事务正在执行,试图更新同一行时,会发生什么?交易有一个由其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. 两个更新的序列化级别
  2. 交易开始的顺序
  3. 事务写入此行页面的顺序是什么

更新:Laurenz是正确的。稍后在一个链接指南中,更新执行方式的确证伪代码是:

(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的行锁定效果。

答案比你想象的更简单:行锁阻止对同一行的并发修改,因此问题永远不会出现,更新链也不会分叉。

最新更新