Pau*_*per 11 postgresql concurrency mvcc
我的理解是更新锁定一个元组,将其标记为已删除,然后添加一个新元组。
换句话说,更新 = 删除 + 插入。
或者我曾经相信。但在 MVCC 中,更新与删除 + 插入之间似乎存在一些根本不同。
设置:
CREATE TABLE example (a int PRIMARY KEY, b int);
INSERT INTO example VALUES (1, 1);
Run Code Online (Sandbox Code Playgroud)
方法一:更新
CREATE TABLE example (a int PRIMARY KEY, b int);
INSERT INTO example VALUES (1, 1);
Run Code Online (Sandbox Code Playgroud)
方法二:删除插入
-- session A session B
BEGIN;
UPDATE example SET b = 2 WHERE a = 1;
DELETE FROM example WHERE a = 1;
COMMIT;
-- now there are 0 rows in table example (1 row was deleted by session B)
Run Code Online (Sandbox Code Playgroud)
因此
-- session A session B
BEGIN;
DELETE FROM example WHERE a = 1;
INSERT INTO example VALUES (1, 2);
DELETE FROM example WHERE a = 1;
COMMIT;
-- now there is 1 row in table example (0 rows deleted by session B)
Run Code Online (Sandbox Code Playgroud)
不同于
UPDATE example SET b = 2 WHERE a = 1;
Run Code Online (Sandbox Code Playgroud)
我如何理解更新的 MVCC 性质?元组是否具有某种在更新过程中保留的 MVCC“身份”?它是什么?
Lau*_*lbe 14
是的,UPDATE和DELETE+之间是有区别的INSERT。
让我们使用pageinspect扩展来查看元组和元组标题。
如果你想重复我的实验,你必须在两者之间删除并重新创建表。此外,如果您在检查行之前选择了行,则可能会有其他标志(提示位)。
的意义infomask2和infomask可以发现src/include/access/htup_details.h,看到报价在回答结束。
UPDATE:SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask2, t_infomask, t_attrs
FROM heap_page_item_attrs(get_raw_page('example', 0), 'example');
lp | t_xmin | t_xmax | t_ctid | t_infomask2 | t_infomask | t_attrs
----+--------+--------+--------+-------------+------------+-------------------------------
1 | 380943 | 380944 | (0,2) | 16386 | 256 | {"\\x01000000","\\x02000000"}
2 | 380944 | 0 | (0,2) | 32770 | 10240 | {"\\x01000000","\\x02000000"}
(2 rows)
Run Code Online (Sandbox Code Playgroud)
第一个元组是死元组。它t_ctid已更改为指向更新版本。
这是关键点之一,所以让我扩展一下:ctid元组的组合是块号和“行指针”(lp在查询结果中。t_ctid通常是多余的,但在这种情况下它用于指向新的行版本。这是原始元组和更新版本之间的链接。
t_infomask2是 2(列数)加上HEAP_HOT_UPDATED,因此该行收到了HOT 更新(块中有足够的空间,并且没有索引)。t_infomask是HEAP_XMIN_COMMITTED(提示位)。
第二个元组是新版本。
t_infomask2是 2 plus HEAP_ONLY_TUPLE,所以这是“仅堆元组”,只能通过ctid旧版本的更新才能访问。t_infomaskis HEAP_XMAX_INVALID(true, it is 0) plus HEAP_UPDATED(这是更新的版本)。
DELETE+ 之后INSERT:SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask2, t_infomask, t_attrs
FROM heap_page_item_attrs(get_raw_page('example', 0), 'example');
lp | t_xmin | t_xmax | t_ctid | t_infomask2 | t_infomask | t_attrs
----+--------+--------+--------+-------------+------------+-------------------------------
1 | 380958 | 380961 | (0,1) | 8194 | 256 | {"\\x01000000","\\x02000000"}
2 | 380961 | 0 | (0,2) | 2 | 2048 | {"\\x01000000","\\x02000000"}
(2 rows)
Run Code Online (Sandbox Code Playgroud)
同样,第一个元组是死元组。
t_infomask2是 2 plus HEAP_KEYS_UPDATED(这是一个删除或更新的元组),并且t_infomask是HEAP_XMIN_COMMITTED(元组在被删除之前是有效的)。
第二个元组是插入的元组:
t_infomask2是 2 加,并且t_infomask是HEAP_XMAX_INVALID(它是 0),所以这是一个新的元组。
在READ COMMITTED隔离级别,事务总是看到行的最新提交版本。的DELETE会话B具有锁定的行和由堵塞UPDATE或DELETE在会话A.
文档解释了释放锁时会发生什么:
UPDATE、DELETE、SELECT FOR UPDATE和SELECT FOR SHARE命令的行为与SELECT在搜索目标行方面:他们只会找到在命令开始时提交的目标行。但是,这样的目标行在找到时可能已经被另一个并发事务更新(或删除或锁定)。在这种情况下,潜在的更新者将等待第一个更新事务提交或回滚(如果它仍在进行中)。如果第一个更新程序回滚,那么它的效果就无效了,第二个更新程序可以继续更新最初找到的行。如果第一个更新程序提交,第二个更新程序将在第一个更新程序删除该行时忽略该行,否则它将尝试将其操作应用于该行的更新版本。命令的搜索条件(WHERE子句)被重新评估以查看该行的更新版本是否仍然匹配搜索条件。如果是,则第二个更新程序使用该行的更新版本继续其操作。
在UPDATE旧行版本和新行版本之间存在链接的情况下,因此PostgreSQL锁定并删除新行版本,而在DELETE+的情况下,INSERT锁消失后没有行的有效版本,什么也没有被删除。
因此,虽然在许多方面UPDATE和PostgreSQL 中的DELETE+INSERT非常相似,但它们并不相同:在第二种情况下,删除行和插入行之间没有联系。
infomask和infomask2t_infomask:
SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask2, t_infomask, t_attrs
FROM heap_page_item_attrs(get_raw_page('example', 0), 'example');
lp | t_xmin | t_xmax | t_ctid | t_infomask2 | t_infomask | t_attrs
----+--------+--------+--------+-------------+------------+-------------------------------
1 | 380943 | 380944 | (0,2) | 16386 | 256 | {"\\x01000000","\\x02000000"}
2 | 380944 | 0 | (0,2) | 32770 | 10240 | {"\\x01000000","\\x02000000"}
(2 rows)
Run Code Online (Sandbox Code Playgroud)
t_infomask2:
SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask2, t_infomask, t_attrs
FROM heap_page_item_attrs(get_raw_page('example', 0), 'example');
lp | t_xmin | t_xmax | t_ctid | t_infomask2 | t_infomask | t_attrs
----+--------+--------+--------+-------------+------------+-------------------------------
1 | 380958 | 380961 | (0,1) | 8194 | 256 | {"\\x01000000","\\x02000000"}
2 | 380961 | 0 | (0,2) | 2 | 2048 | {"\\x01000000","\\x02000000"}
(2 rows)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1148 次 |
| 最近记录: |