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_infomask
is 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
和infomask2
t_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 次 |
最近记录: |