【问题标题】:Does the ctid chain in Postgres fork under concurrent update of a row?Postgres 中的 ctid 链是否在行的并发更新下分叉?
【发布时间】:2021-04-12 05:16:49
【问题描述】:

我正在阅读 this guidethis guide 以更好地了解 postgres 内部是如何工作的,而且大部分事情都是有意义的。但是,我有一个关于并发更新将如何影响ctid 链的问题。

据我了解,ctids 指向“下一个”(页面、指针)组合来描述对给定行的修订。但是,当两个并发事务正在执行并试图更新同一行时会发生什么?事务具有由它们的 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. 事务写入该行页面的顺序?

更新:劳伦兹是正确的。稍后在链接指南之一中证实了如何执行更新的伪代码是:

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

【问题讨论】:

    标签: postgresql


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-16
      • 2020-11-21
      • 1970-01-01
      相关资源
      最近更新 更多