如何解决可序列化隔离级别混淆 - 写偏斜Postgres
我正在运行 Postgres12 并且对可序列化事务级别的行为感到困惑。
表格:
活动
- id
- 难度
经理
- id
- 级别
预期行为(在序列化事务中):
- 检查是否有 7 个或更多难度事件=2
- 如果是,请插入 level=2 的经理
我在可序列化中运行以下事务,但没有看到我预期的行为(期望可序列化事务检测 2 个会话之间的写入偏差)
-- session 1:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT count(*) from events WHERE difficulty=2
-- RETURNS 7
-- Now start session 2
-- session 2:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT id FROM events WHERE difficulty=2 LIMIT 1;
/*
id
----
4
*/
UPDATE events SET difficulty=1 WHERE id=4;
COMMIT;
现在只有6个难度=2的事件
-- back in session 1
-- since we have counted 7 events of difficulty=2 in this session,create a manager
INSERT INTO manager (level) VALUES (2);
COMMIT;
-- Expected write skew to be detected here bc the read event rows have seen updates (only 6 actually)
不幸的是,我们的最终状态现在是 6 个难度 = 2 的事件和 2 级经理。 为什么可序列化隔离不能防止这种写倾斜? 我对可序列化隔离用例有什么误解?为什么难度=2 的事件不被谓词锁定或某种隔离机制锁定或监视?
图片清晰
解决方法
SERIALIZABLE
表示有一种方法可以串行执行事务(一个接一个),这样效果是一样的。在您的情况下,这种等效的串行执行将首先运行会话 1,然后运行会话 2,效果相同。
您可以说会话 1 在会话 2 之前“逻辑地”执行。
,思考后回答我自己的问题!
序列化检查并没有阻止两个会话的提交,因为有可能序列化两个事务并且仍然以 2 级管理器和 6 个难度 = 2 的事件结束。
例如
- 运行会话 1(检查是否有 7 个难度=2 的事件,创建经理级别=2)COMMIT;
- 运行会话 2(删除一个事件,现在 6 个事件的难度=2)COMMIT;
^输出 = 6 个事件,1 个经理
这与并发运行的结果相同,因此这被视为这两个可序列化事务的“可接受”状态。
如果您想阻止这种行为,可以将会话 2 更新为以下内容
begin transaction isolation level serializable;
select count(*) from manager where level=2;
--if no managers
update events set difficulty=1 where id=4;
现在没有合乎逻辑的方法来结束具有序列化顺序的状态 6 事件 1 管理器。顺序排序的两种可能结果是
- 会话 1 运行
- 会话 2 运行
^output = 7 个事件 1 个经理
- 会话 2 运行
- 会话 1 运行
^output = 6 个事件 0 个经理
因此,在这种情况下(使用更新的会话 2),您的一项交易将被阻止,因为这些交易不再可序列化。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。