[英]Postgres, update and lock ordering
我正在研究Postgres 9.2。
有2个UPDATE,每个都在自己的交易中。 一个看起来像:
UPDATE foo SET a=1 WHERE b IN (1,2,3,4);
另一个是类似的:
UPDATE foo SET a=2 WHERE b IN (1,2,3,4);
这些可能同时运行,实际上在'IN'表达式中有500+。 我有时会看到死锁。 确实,“IN”表达式中的项目顺序实际上可能不会影响真正的锁定顺序吗?
UPDATE
命令中没有ORDER BY
。
但是有SELECT
。 在子查询中使用行级锁定和FOR UPDATE
子句 :
UPDATE foo f
SET a = 1
FROM (
SELECT b FROM foo
WHERE b IN (1,2,3,4)
ORDER BY b FOR UPDATE
) upd
WHERE f.b = upd.b;
当然, b
必须是UNIQUE
或者你需要在ORDER BY
子句中添加更多表达式以使其明确无误。
并且您需要对表上的所有 UPDATE
, DELETE
和SELECT .. FOR UPDATE
语句强制执行相同的顺序。
相关,更多细节:
是。 我认为这里的主要问题是IN
检查指定集合中的成员资格,但不会在UPDATE
上赋予任何类型的顺序,这反过来意味着没有赋予锁定顺序的具体排序。
UPDATE
语句中的WHERE
子句的行为基本上与SELECT
行为相同。 例如,我经常使用SELECT
模拟UPDATE
以检查将更新的内容,以确定它是我所期望的。
考虑到这一点,以下使用SELECT
示例演示了IN
本身不会赋予顺序:
鉴于此架构/数据:
create table foo
(
id serial,
val text
);
insert into foo (val)
values ('one'), ('two'), ('three'), ('four');
以下查询:
select *
from foo
where id in (1,2,3,4);
select *
from foo
where id in (4,3,2,1);
产生完全相同的结果 - 从id
1-4开始的行。
即使这样也无法保证 ,因为我没有在select中使用ORDER BY
。 相反,如果没有它, Postgres会使用服务器决定的最快顺序(参见Postgres SELECT doc中关于ORDER BY
的第8点)。 给定一个相当静态的表,它通常与插入的顺序相同(就像这里的情况一样)。 然而,没有任何保证,如果桌子上有很多流失(许多死元组,行删除等),那么情况就不太可能了。
我怀疑这是你的UPDATE
发生的事情。 有时候 - 如果不是大多数时候 - 它可能以数字顺序结束,如果插入行的方式相同,但没有什么可以保证的,并且你看到死锁的情况可能是数据的情况已更改,以使一个更新的顺序与另一个更新。
sqlfiddle与上面的代码。
可能的修复/解决方法:
就您可以采取的措施而言,根据您的要求,有多种选择。 你可以在表上明确地取出一个表锁,虽然那当然会产生序列化更新的效果,这可能被证明是一个太大的瓶颈。
另一个仍然允许并发的选项是在Python中使用动态SQL显式迭代项目。 这样,您将拥有一组始终以相同顺序发生的一行更新,并且由于您可以确保一致的顺序,因此正常的Postgres锁定应该能够处理并发而不会发生死锁。
这不会像纯SQL中的批量更新那样好,但它应该解决锁定问题。 提高性能的一个建议是每COMMIT
只执行一次COMMIT
,而不是每一行之后 - 这样可以节省大量开销。
另一种选择是在用PL / pgSQL编写的Postgres函数中进行循环。 然后可以在Python中外部调用该函数,但是循环将在服务器端完成(也明确),这可以节省一些开销,因为循环和UPDATEs
完全在服务器端完成而不必去通过电线每次循环迭代。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.