我有点想知道更新我正在制作一张大桌子,我是否需要担心锁定。
我的桌子看起来像这样:
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行并最终释放锁。在锁定到位之前,其他工作人员正在等待锁定释放。我是对的还是我想念的?
感谢您的帮助!
答案 0 :(得分:4)
UPDATE
会锁定该行,因此您无需先锁定它。如果您同时尝试UPDATE
重叠行集,则第二个UPDATE
将等待第一个事务提交或回滚。
您的方法的一个大问题 - 除了UPDATE
没有LIMIT
子句的事实 - 是多个工作人员都会尝试抓取相同的行。这是发生的事情:
worker1:过滤表以查找200行并锁定它们 worker1:开始更新行 worker2:过滤表以查找200行 worker2:尝试开始更新行,但选择了与worker1相同的行 所以它阻止了worker1的锁定 worker1:完成更新行 worker2:锁定释放后,重新检查WHERE条件并找出没有行 因为worker1已经更新了它们。更新零行。 ......并重复一遍!
您需要:
对于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”来调整内容。