为什么非删除行中postgres表中的xmax系统列不为零?

时间:2018-04-06 14:39:14

标签: sql postgresql

我有以下表格:

       Table "public.product"
 Column |  Type   |                      Modifiers
--------+---------+------------------------------------------------------
 id     | integer | not null default nextval('product_id_seq'::regclass)
 name   | text    | not null
Indexes:
    "product_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "stock" CONSTRAINT "stock_product_id_fkey" FOREIGN KEY (product_id) REFERENCES product(id)

此表有2条记录: -

postgres=# select xmin, xmax, cmin, cmax, * from product;
  xmin   |  xmax   | cmin | cmax | id |  name
---------+---------+------+------+----+---------
 3126848 | 3126856 |    0 |    0 |  1 | Parle-G
 3126849 | 3126858 |    0 |    0 |  2 | Pepsi
(2 rows)

我有以下与xmax和cmin列有关的问题: -

  1. 根据postgres文档,xmax存储删除此行的事务的id。但由于我的行尚未删除,为什么它包含非零值。

  2. Postgres docs说cmin包含事务中的语句序列号,它创建了这一行。根据SQL标准,每个语句本身都是一个事务,因此以这种方式,它必须包含cmin列的非零数字。

  3. 请纠正我,我错了。提前谢谢。

1 个答案:

答案 0 :(得分:5)

我先回答你的第二个问题,因为这很简单:

cmin从零开始计数,因此cmin为零意味着这是事务中的第一个语句。如果您的所有交易都包含一个语句,那么您可以期望cmin始终为零。

关于xmax

的含义

除了存储删除该行的事务的编号外,此系统列还用于存储行锁。它们存储在行本身而不是共享内存中,以避免锁表溢出。

行锁以两种不同的方式存储:

  • 如果只有一个交易持有一行锁,则交易号存储在xmax

  • 如果一个行上有多个(共享)锁,则会创建一个 multixact 结构,其编号存储在xmax中。

xmax的不同用法之间没有冲突,因为数据库有其他信息:

  • 表格行中的其他标记(系统列不可见)消除了xmax的含义歧义。

  • 提交日志存储交易是否已提交。只有已提交事务删除的行才会被删除。

总结一下,如果你在xmax中看到一个非零值,那可能意味着四件事:

  • 该行已被删除或更新,您的查询正在使用比修改事务更早的快照运行。

  • 该行已被回滚的事务删除或更新。

  • 该行已锁定或已在过去的某个时间点被锁定,您会看到锁定事务的事务ID。

  • 如上所述,但您会看到 multixact 值。您可以使用函数pg_get_multixact_members查看哪些交易属于它。

您可能有兴趣阅读my blog post,我会更详细地探讨这个问题。