2014-09-24 55 views
0

有一个潜在的大型更新语句可以更改表上的布尔标志和时间戳列。如何执行不会锁定其他查询的更新?

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

更新操作不应该锁定表,并且如果可能同时运行的其他查询得到陈旧的数据,我非常乐意。

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

在这种情况下,如果读取操作在更新语句正在处理时为布尔标志和时间戳列获取不正确的值,那就好了。

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

+2

作家不会阻止Postgres中的读者,读者也不会阻止作者。 Postgres将只会锁定你更新的行,并会阻止其他会话更新它们。更新语句永远不会锁定整个表(除非更新所有行,但仍然可以查询该表)否将禁止选择语句。这就是Postgres的工作原理,没有什么是你需要做的。 – 2014-09-24 15:58:44

+0

@a_horse_with_no_name哦,我明白了,好奇,你知道mysql是否以同样的方式行事? – 2014-09-24 16:34:01

+0

我认为是的(可能会出现一些锁升级,但我不确定。我几乎没有必要使用MySQL)。但我会说现代DBMS将(应该)以这种方式行事。 – 2014-09-24 17:16:22

回答

0

由于@a_horse_with_no_name笔记,一个UPDATE(或INSERTDELETE)并不妨碍在PostgreSQL的并发SELECT S,除非这些SELECT就做明确的行与FOR UPDATEFOR SHARE锁定。

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

任何UPDATE S或DELETE s表示影响的行已经被UPDATE d将是上的行锁阻塞直到现有UPDATE完成。但是,在这里更新顺序有一个皱纹。

如果你的大更新按顺序扫描表,更新每一行,然后你做另一个小的UPDATE以其他顺序扫描表来选择要更新的行,你可以找到一个死锁。大的更新可能会锁定id = 1000的行,并试图锁定id = 1001的行。但是你的较新的小更新已经在id = 1001上有一个锁,并试图获得id = 1000的锁。他们也无法获得他们想要的锁,所以他们被卡住了。 PostgreSQL检测到这个并且终止其中一个死锁检测错误的语句。有无法保证哪些声明将被中止。

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

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