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

May*_*tel 5 sql postgresql vacuum sql-update

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

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

表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';
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

-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';
Run Code Online (Sandbox Code Playgroud)

具有类似的运行时间(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';
Run Code Online (Sandbox Code Playgroud)

然后查询运行〜500ms.

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

UPDATE H SET release='1'
FROM A
where A.state!='done' AND release!='1' AND A.id=H.a;
Run Code Online (Sandbox Code Playgroud)

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

我在哪里可以离开?

-xxxx-

VACUUM ANALYZE已作为"例行维护"的一部分添加,其中应用程序大约每分钟运行一次左右,而不依赖于正在运行的任何自动真空.

另外,重写第二个查询以消除已知的慢速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');
Run Code Online (Sandbox Code Playgroud)

Qua*_*noi 2

PostgreSQL实现MVCC.

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

这会减慢查询速度。

你应该VACUUM及时跑步。

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

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