优化 Postgres 中的并发更新

Ale*_*nko 11 postgresql deadlock locking update

我正在运行这样的并发 Postgres 查询:

UPDATE foo SET bar = bar + 1 WHERE baz = 1234
Run Code Online (Sandbox Code Playgroud)

每个查询都会影响固定的 K 行数,我找不到强制执行更新行顺序的方法,最终导致死锁。目前我通过手动执行订单来解决这个问题,但这意味着我必须执行比平时更多的查询,同时还将搜索复杂度从 O(log N + K) 提高到 O(K log N)。

有没有办法提高性能而不会最终容易陷入死锁?我怀疑如果Postgres 以扫描它们的相同顺序更新行,用(baz)索引替换(baz, id)索引可能会起作用,这是一种值得追求的方法吗?

Erw*_*ter 16

有没有ORDER BYSQL UPDATE命令。Postgres 以任意顺序更新行:

为了绝对确定地避免死锁,您可以在可序列化事务隔离中运行您的语句。但这更昂贵,您需要准备在序列化失败时重复命令。

您最好的做法可能是SELECT ... ORDER BY ... FOR UPDATE在子查询中或SELECT事务中的独立对象中显式锁定- 在默认的“已提交读”隔离级别中。在 pgsql-general 上引用 Tom Lane 的话

应该没问题 --- FOR UPDATE 锁定始终是 SELECT 管道中的最后一步。

这应该可以完成这项工作:

BEGIN;

SELECT 1
FROM   foo 
WHERE  baz = 1234
ORDER  BY bar
FOR    UPDATE;

UPDATE foo
SET    bar = bar + 1
WHERE  baz = 1234;

COMMIT;
Run Code Online (Sandbox Code Playgroud)

多列索引(baz, bar)可能非常适合性能。但是由于bar显然更新了很多,所以单列索引(baz)可能会更好。取决于几个因素。每行多少行baz?如果没有多列索引,是否可以进行HOT 更新?...

如果 baz同时被更新,还有一个不太可能的极端情况对冲突的机会(每个文件)

这是可能的SELECT,在运行命令READ COMMITTED 事务隔离级别,并使用ORDER BY和锁定子句返回行乱序。...

此外,如果您应该有一个涉及 的唯一约束bar,请考虑一个DEFERRABLE约束以避免同一命令中的唯一违规。相关回答: