【问题标题】:Postgres 8.4.4 (x32 on Win7 x64) very slow UPDATE on small tablePostgres 8.4.4(Win7 x64 上的 x32)小表上的更新非常慢
【发布时间】:2010-12-24 18:06:04
【问题描述】:

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

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 发行说明相关的错误修复。谁能帮我理解发生了什么?谢谢,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';

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

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

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

【问题讨论】:

  • 不更新表格怎么样?只需查看您需要在 W 和 H 表上获取的信息
  • 请发布两个更新的计划。
  • @Hao:我对这个建议感到困惑。这不是读操作,我实际上是在修改每个表中的内容。
  • @Quassnoi:第一个 UPDATE 计划:“Seq Scan on W (cost=0.00..2.40 rows=1 width=52)”“过滤器:((state ALL ('{this, that}'::Wstate[])) AND (losttime 1::smallint) AND (NOT (SubPlan 1)))" " SubPlan 1" " -> Materialize (cost=2706.66..3735.35 rows=73969 width=4)" " -> Seq Scan on A (cost =0.00..2343.69 rows=73969 width=4)" " Filter: (state 'done'::Astate)" 我对 A 的 seq 扫描感到困惑:我在 'state.' 上有一个索引。跨度>
  • 请不要在 cmets 中发布代码。相反,请更新您自己的帖子。

标签: sql postgresql sql-update vacuum


【解决方案1】:

PostgreSQL 实现MVCC

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

这会减慢查询速度。

您应该及时运行VACUUM

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

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

【讨论】:

  • 手册上说每天一次 VACUUM 就足够了。我正在更新 W 表中的行,频率约为秒。 Autovacuum naptime 默认为 1 分钟。数学对我来说并没有加起来,除非 autovacuum 由于某种原因根本没有运行。它设置为在 postgresql.conf 中运行
  • @Mayur:真空吸尘器之间的间隔可能会根据您的负载而有所不同。 autovacuum_naptime 只定义了守护进程唤醒并检查是否需要清理的时间段,它不一定每分钟运行一次 VACUUM。手动执行VACUUM 后查询是否恢复正常速度?
  • 对不起,我想你一定是在我回复后编辑了你的回复。在尝试运行 VACUUM 之前,我仍在“损坏”状态下运行其他几个测试。因为问题需要一些时间才能变得非常明显,所以我现在尽可能多地进行分析。将报告 VACUUM 是否工作。 (但我会说,昨天我从 pgAdminIII 运行了一个,但没有看到改进的行为。)
  • 我从 pqAdminIII 查询窗口运行了 VACUUM。运行大约需要 8 秒,但我引用的第二个更新在 4 分钟后仍在运行,所以我认为这足以说明它没有帮助。如果我需要运行 VACUUM FULL,那么它可能会破坏交易,因为该数据库需要具有高可用性。不会有“停机时间”,可以长时间完全锁定表。 (叹气)我很乐意尝试其他建议...
  • 我运行了一个 VACUUM FULL,执行时间为 18 分钟。我引用的第二个 UPDATE 命令在 60 秒后仍在运行......
【解决方案2】:

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

另一种选择是表被锁定。查看pg_stat_activitypg_locks 找出答案。

【讨论】:

  • 是的,听起来像是被锁定的记录。
  • pg_total_relation_size == 750 kB
  • 查看了 pg_stat_activity 和 pg_locks 视图。没有什么让我跳出来,每个视图中都有几个条目,但没有什么能让我认为大量的行仍然被锁定。 (我不确定为什么 CPU 会锁定在锁定的行上,我预计在这种情况下 CPU 利用率会非常低。)在这些视图中我应该查看一些具体的内容吗?谢谢
【解决方案3】:

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

【讨论】:

  • 我正在通过 python 适配器 psycopg 访问 postgres。我在创建连接时打开自动提交,因为这些更新中的每一个都可以自主运行,它们不需要是复合原子操作。您能帮我理解为什么您怀疑交易未能完成吗?为什么这会导致查询缓慢,为什么在游标/连接被(可能不正确)破坏时我不会收到错误?数据库中的数据是有效的,所以我没有看到那里出现故障。请更深入地了解您的思路?
  • 好吧,我不确定,但我最近在类似的情况下看到性能下降,因为实际上没有关闭交易是问题所在。如果您确定所有交易都已提交,那我一定是错的,而且一定是别的东西。
  • 当我杀死一个打开连接的客户端时,我的 postgres 服务器崩溃了,但除此之外,数据库中的数据看起来“正确”。我会留意连接问题。谢谢。
猜你喜欢
  • 2021-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多