我有一个非常简单的更新声明:
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');
答案 0 :(得分:2)
PostgreSQL
实施MVCC
。
这意味着每次进行更新时,都会创建一个新的行副本,并将旧的副本标记为已删除(但不会被物理删除)。
这会减慢查询速度。
您应该及时运行VACUUM
。
PostgreSQL 8.4.4
运行autovacuum
守护程序来执行此操作,但在安装时可能会出现一些问题。
手动运行VACUUM
时情况有所改善吗?
答案 1 :(得分:2)
检查pg_total_relation_size('tablename')
您的牌桌是否膨胀不成比例。如果是这种情况,您可能需要调整autovacuum配置。
另一种选择是表被锁定。查看pg_stat_activity
或pg_locks
以查找。
答案 2 :(得分:1)
我认为你没有正确关闭交易。