为什么PostgreSQL可序列化的交易认为这是冲突?
在我的理解中,PostgreSQL使用某种监视器来猜测可序列化隔离级别是否存在冲突.许多示例都是关于在并发事务中修改相同资源,并且可序列化事务很有效.但我想以另一种方式测试并发问题.
我决定测试2个用户修改他们自己的帐户余额,并希望PostgreSQL足够智能,不会将其检测为冲突,但结果不是我想要的. 下面是我的表,有4个帐户属于2个用户,每个用户都有一个支票帐户和一个储蓄帐户. create table accounts ( id serial primary key,user_id int,type varchar,balance numeric ); insert into accounts (user_id,type,balance) values (1,'checking',1000),(1,'saving',(2,1000); 表数据如下: id | user_id | type | balance ----+---------+----------+--------- 1 | 1 | checking | 1000 2 | 1 | saving | 1000 3 | 2 | checking | 1000 4 | 2 | saving | 1000 现在我为2个用户运行2个并发事务.在每笔交易中,我都会用一些钱减少支票账户,并检查用户的总余额.如果它大于1000,则提交,否则回滚. 用户1的例子: begin; -- Reduce checking account for user 1 update accounts set balance = balance - 200 where user_id = 1 and type = 'checking'; -- Make sure user 1's total balance > 1000,then commit select sum(balance) from accounts where user_id = 1; commit; 用户2是相同的,除了user_id = 2,其中: begin; update accounts set balance = balance - 200 where user_id = 2 and type = 'checking'; select sum(balance) from accounts where user_id = 2; commit; 我首先提交用户1的交易,毫无疑问它成功了.当我提交用户2的事务时,它失败了. ERROR: could not serialize access due to read/write dependencies among transactions DETAIL: Reason code: Canceled on identification as a pivot,during commit attempt. HINT: The transaction might succeed if retried. 我的问题是: >为什么PostgreSQL认为这2个交易是冲突的?我为所有SQL添加了user_id条件,并且不修改user_id,但所有这些都没有效果.
您可以使用以下索引解决此问题:
CREATE INDEX accounts_user_idx ON accounts(user_id); 由于示例表中的数据太少,您必须告诉PostgreSQL使用索引扫描: SET enable_seqscan=off; 现在你的例子将起作用! 如果这看起来像黑魔法,请查看SELECT和UPDATE语句的查询执行计划. 如果没有索引,两者都将在表上使用顺序扫描,从而读取表中的所有行.因此,两个事务都将在整个表上以SIReadLock结束. 这会触发序列化失败. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |