PostgreSQL Upsert differentiate inserted and updated rows using system columns XMIN, XMAX and others
免责声明:理论问题。
这里询问了几个有关如何区分PostgreSQL
这是一个简单的例子:
1 2 3 4 5 6 7 8 9 10 11 12 | CREATE TABLE t(i INT PRIMARY KEY, x INT); INSERT INTO t VALUES(1,1); INSERT INTO t VALUES(1,11),(2,22) ON conflict(i) do UPDATE SET x = excluded.i*11 returning *, xmin, xmax; ╔═══╤════╤══════╤══════╗ ║ i │ x │ xmin │ xmax ║ ╠═══╪════╪══════╪══════╣ ║ 1 │ 11 │ 7696 │ 7696 ║ ║ 2 │ 22 │ 7696 │ 0 ║ ╚═══╧════╧══════╧══════╝ |
因此,
IMO此处不太清楚解释
是否可以将逻辑基于这些列?关于系统列(源代码除外),还有什么更重要的解释吗?
最后我对更新/插入行的猜测正确吗?
我认为这是一个有趣的问题,值得深入回答。如果它有点长,请忍受。
简而言之:您的猜测是正确的,您可以使用以下
1 | RETURNING (xmax = 0) AS inserted |
现在详细说明:
更新一行时,PostgreSQL不会修改数据,而是创建该行的新版本;当不再需要旧版本时,将通过autovacuum删除。行的一个版本称为元组,因此在PostgreSQL中每行可以有多个元组。
如文档中所述,它可以是删除(或更新)元组的事务的事务ID(" tuple"是" row"的另一个词)。只有交易ID在
如果只有一个事务在该行上具有锁,则
您可以安装contrib模块
我运行了您的示例,这是我使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | SELECT *, ctid, xmin, xmax FROM t; ┌───┬────┬───────┬────────┬────────┐ │ i │ x │ ctid │ xmin │ xmax │ ├───┼────┼───────┼────────┼────────┤ │ 1 │ 11 │ (0,2) │ 102508 │ 102508 │ │ 2 │ 22 │ (0,3) │ 102508 │ 0 │ └───┴────┴───────┴────────┴────────┘ (2 ROWS) SELECT lp, lp_off, t_xmin, t_xmax, t_ctid, to_hex(t_infomask) AS t_infomask, to_hex(t_infomask2) AS t_infomask2 FROM heap_page_items(get_raw_page('laurenz.t', 0)); ┌────┬────────┬────────┬────────┬────────┬────────────┬─────────────┐ │ lp │ lp_off │ t_xmin │ t_xmax │ t_ctid │ t_infomask │ t_infomask2 │ ├────┼────────┼────────┼────────┼────────┼────────────┼─────────────┤ │ 1 │ 8160 │ 102507 │ 102508 │ (0,2) │ 500 │ 4002 │ │ 2 │ 8128 │ 102508 │ 102508 │ (0,2) │ 2190 │ 8002 │ │ 3 │ 8096 │ 102508 │ 0 │ (0,3) │ 900 │ 2 │ └────┴────────┴────────┴────────┴────────┴────────────┴─────────────┘ (3 ROWS) |
让我讨论
在行指针(
在行指针2处,我们看到由事务
在行指针3处,我们看到新插入的行。
因此,更新行的非零