如何执行不会锁定其他查询的更新?

时间:2014-09-24 15:42:45

标签: sql postgresql

有一个可能很大的更新语句,用于更改表上的布尔标志和时间戳列。

此操作可能会更新表中可能有几百万行的几千行。

更新操作不应该锁定表,如果可能同时运行的其他查询获得过时数据,我愿意完全没问题。

目标是以不会影响其他读取操作的方式执行更新语句(如果可能,甚至更新)。

在这种情况下,如果在处理update语句时读取操作获取布尔标志和时间戳列的值不正确,则可以正常工作。

对于我可以使用的更新语句,postgresql是否有任何查询优化?鉴于上述宽松的要求?

1 个答案:

答案 0 :(得分:0)

正如@a_horse_with_no_name所述,UPDATE(或INSERTDELETE)不会阻止PostgreSQL中的并发SELECT,除非那些SELECT s使用FOR UPDATEFOR SHARE进行显式行锁定。

因此,在更新运行时,您可以从表中继续SELECTSELECT只会看到旧值。

影响已经UPDATE d行的任何DELETEUPDATE将在行锁上阻止,直到前一个{{1}完成。但是,这里有更新排序的皱纹。

如果你的大更新是按顺序扫描表,按顺序更新每一行,然后再做一个小的UPDATE以其他顺序扫描表以选择要更新的行,你可以登陆陷入僵局。大更新可能已锁定id = 1000的行,并尝试锁定id = 1001的行。但是你的新版小更新已经锁定了id = 1001并试图获得id = 1000的锁定。他们都不能得到他们想要的锁,所以他们被困住了。 PostgreSQL检测到这一点,并使用死锁检测错误中止其中一个语句。 无保证哪个语句将被中止。

为了缓解这种情况,我建议尽可能将您的大UPDATE分成一系列小UPDATE,每个UPDATE超过一系列值。这也将减少数据库必须在表中分配的额外工作空间量,以存储新版本的行,直到更新完成,并且可以清除旧版本。

我希望MySQL + InnoDB的行为类似。当你执行UPDATE时,MySQL + MyISAM将锁定表格,但你不应该使用MyISAM。