5

我有一个非常简单的更新语句:

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

表 W 只有 90 行,但每行的 losttime 和 state 列大约每 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(release) 上放置和删除索引,而行为没有变化。在数据库运行 48 小时并且表 H 有大约 100k 行之后,此查询需要 27 分钟。在查询期间,Postgres 服务器将有一个完全固定的线程(100% CPU 利用率),因此看起来没有任何网络、磁盘等争用。

所以总的来说,我看到的行为是我的数据库按预期运行了大约 5 分钟,然后随着基本维护相关的 UPDATE 命令开始花费越来越长的时间来运行,一切都逐渐停止。到第二天,需要一个小时来完成一个简单的维护周期(一些更新),一开始运行大约 100 毫秒。我似乎很清楚,性能下降与数据库中的信息量呈超线性关系——可能是 N^2 或类似的。

Autovacuum 使用默认设置。我(再次)通读了手册,并没有看到任何让我兴奋的东西。

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

-xxxx-

好的,所以我在这里可能有两个问题。

第一次更新现在似乎运行得很快。不知道发生了什么,所以我会假设我需要更频繁地运行 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';

然后查询在 ~500 毫秒内运行。

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

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

运行大约 140 秒,速度更快,但仍然非常非常慢。

我可以从这里去哪里?

-xxxx-

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');
4

3 回答 3

2

PostgreSQL实现MVCC

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

这会减慢查询速度。

您应该VACUUM及时运行。

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

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

于 2010-12-24T18:10:20.817 回答
2

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

另一种选择是表被锁定。调查pg_stat_activitypg_locks找出。

于 2010-12-24T20:15:29.303 回答
1

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

于 2010-12-24T18:09:11.957 回答