Postgres 8.4.4(Win7 x64上的x32)在小表上非常慢的UPDATE

时间:2010-12-24 18:06:04

标签: sql postgresql sql-update vacuum

我有一个非常简单的更新声明:

UPDATE W SET state='thing'
WHERE state NOT IN ('this','that') AND losttime < CURRENT_TIMESTAMP;

表W只有90行,但每行大约每10秒钟更新一行的丢失时间和状态列。状态和丢失时间(以及主要索引)都有索引。

我注意到大型数据库(即其他表有很多条目,而不是表W)在一段时间内,查询变慢,变慢和变慢。运行48小时后,我通过在PqAdminIII的查询窗口中运行它来计时,它需要17分钟才能执行!

我在另一个显示相同问题的表上有类似的查询:

UPDATE H SET release='1' 
WHERE a NOT IN (SELECT id from A WHERE state!='done') AND release!='1';

H没有任何索引,但我尝试在H(发布)上放置和删除索引而不改变行为。在数据库已经运行48小时并且表H有大约100k行之后,此查询需要27分钟。 Postgres服务器在查询期间将有一个完全挂钩的线程(100%CPU利用率),因此它看起来不像是对网络,磁盘等的任何争用。

所以从广义上来说,我看到的行为是我的数据库按预期运行大约5分钟,然后随着基本维护相关的UPDATE命令开始运行的时间越来越长,所有内容都会停止。到第二天,花一个小时做一个简单的维护周期(一些更新),一开始就运行~100ms。我似乎很清楚,性能下降与数据库中的信息量是超线性的 - 可能是N ^ 2或其他类似的。

使用默认值启用Autovacuum。我仔细阅读了手册,并没有看到任何跳出来的东西。

我在这里挠头。我没有看到任何在9.0.1和9.0.2发行说明中看起来相关的错误修复。谁能帮我理解发生了什么?谢谢,M

-X-X-X-X -

好的,我可能在这里遇到两个问题。

第一次更新似乎现在快速运行。不确定发生了什么,所以我将继续假设我需要更频繁地运行VACUUM / ANALYZE或某种组合 - 比如每分钟左右。我真的很想知道为什么autovacuum不会这样做。

第二次更新继续缓慢运行。查询计划表明索引没有得到有效使用,并且发生了80k * 30k的交叉,这可能是我看起来正在观察的超线性运行时的原因。 (大家都同意这个计划的解释吗?)

我可以将UPDATE转换为SELECT:

SELECT * from H
where a not in (SELECT id from A where state='done') AND release!='1';

具有类似的运行时间(27分钟)。

如果我不信任postgres优化器并执行此操作:

WITH r as (select id from A where state='done')
SELECT a from H 
JOIN on H.a=r.id 
WHERE H.released='0';

然后查询在~500ms内运行。

如何将此知识转换回以可接受的速度运行的更新? 我的尝试:

UPDATE H SET release='1'
FROM A
where A.state!='done' AND release!='1' AND A.id=H.a;

在大约140秒内运行,这更快,但仍然非常慢。

我可以从哪里离开?

-X-X-X-X -

VACUUM ANALYZE已添加为“例行维护”的一部分,其中应用程序大约每分钟运行一次左右,而不管正在运行的任何autovacuum。

另外,重写第二个查询以消除已知的慢速NOT IN子句,将其替换为“Left Anti-Semi Join”(呵呵?)

UPDATE H SET release='1' 
WHERE release='0' AND NOT EXISTS (SELECT * FROM A WHERE id=H.a AND state!='done');

3 个答案:

答案 0 :(得分:2)

PostgreSQL实施MVCC

这意味着每次进行更新时,都会创建一个新的行副本,并将旧的副本标记为已删除(但不会被物理删除)。

这会减慢查询速度。

您应该及时运行VACUUM

PostgreSQL 8.4.4运行autovacuum守护程序来执行此操作,但在安装时可能会出现一些问题。

手动运行VACUUM时情况有所改善吗?

答案 1 :(得分:2)

检查pg_total_relation_size('tablename')您的牌桌是否膨胀不成比例。如果是这种情况,您可能需要调整autovacuum配置。

另一种选择是表被锁定。查看pg_stat_activitypg_locks以查找。

答案 2 :(得分:1)

我认为你没有正确关闭交易。