在PostgreSQL中,对具有锁定冲突的同一个表中的不同行执行多个UPDATES?

时间:2012-08-01 14:19:03

标签: postgresql locking

我有点想知道更新我正在制作一张大桌子,我是否需要担心锁定。

我的桌子看起来像这样:

CREATE TABLE "ItemsToProcess"( 
"id" text, 
"WorkerInstanceId" text, 
"ProcessingStartTime" timestamp with time zone, 
"UpdatedTime" timestamp with time zone, 
CONSTRAINT "ITP_PK" PRIMARY KEY ("id")
)WITH (
  OIDS=FALSE
);

最初,这个表中有大约200万行,只有ID填入,WorkerInstanceId和两个时间戳默认为null,并且在运行开始时。

会发生一些工作者应用程序(至少两个,但生产中约为10-13)将从该表中标记一批ID-s(我计划将batchSize设置为200)以进行处理。处理过程中发生的事情现在并不重要。 批处理的标记如下所示:

UPDATE "ItemsToProcess" 
   SET "WorkerInstanceId" = ?, "ProcessingStartTime" = current_timestamp()
 WHERE "WorkerInstanceId" is NULL
 LIMIT 200;

我的问题是,在进行更新之前,我是否需要担心锁定我要更新的行?

Postgres文档说:

  

ROW EXCLUSIVE

     

与SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE和ACCESS EXCLUSIVE锁定模式冲突。

     

命令UPDATE,DELETE和INSERT在目标表上获取此锁定模式(除了任何其他引用表上的ACCESS SHARE锁定)。通常,此锁定模式将由修改表中数据的任何命令获取。

所以我认为每当其中一个工作者进行此更新时,整个表都会被锁定,更新200行并最终释放锁。在锁定到位之前,其他工作人员正在等待锁定释放。我是对的还是我想念的?

感谢您的帮助!

2 个答案:

答案 0 :(得分:4)

UPDATE会锁定该行,因此您无需先锁定它。如果您同时尝试UPDATE重叠行集,则第二个UPDATE将等待第一个事务提交或回滚。

您的方法的一个大问题 - 除了UPDATE没有LIMIT子句的事实 - 是多个工作人员都会尝试抓取相同的行。这是发生的事情:

worker1:过滤表以查找200行并锁定它们 worker1:开始更新行 worker2:过滤表以查找200行 worker2:尝试开始更新行,但选择了与worker1相同的行          所以它阻止了worker1的锁定 worker1:完成更新行 worker2:锁定释放后,重新检查WHERE条件并找出没有行          因为worker1已经更新了它们。更新零行。 ......并重复一遍!

您需要:

  • 让中心queue以适当的并发安全方式分发行;或
  • 指定工作人员不重叠的ID范围以便
  • 工作

对于LIMIT - 您可以使用WHERE id IN (SELECT t.id FROM thetable t LIMIT 200 ORDER BY id) - 但是两个工作人员选择要更新的同一行集时会遇到同样的问题。

答案 1 :(得分:1)

你遗漏了几件事。

首先,PostgreSQL没有为更新提供“LIMIT”选项。请参阅docs for UPDATE

其次,请注意“ROW EXCLUSIVE”不与自身冲突,它与“SHARE ROW EXCLUSIVE”冲突不同。因此,您的UPDATE语句可以安全地从多个worker中同时运行。你仍然希望你的UPDATE时间很短。但是,如果遇到问题,您已经通过降低“batchSize”来调整内容。