繁体   English   中英

Postgres,更新和锁定订单

[英]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子句中添加更多表达式以使其明确无误。

并且您需要对表上的所有 UPDATEDELETESELECT .. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM