Postgres 运行缓慢的删除查询

Posted

技术标签:

【中文标题】Postgres 运行缓慢的删除查询【英文标题】:Postgres slow running delete query 【发布时间】:2017-07-30 18:40:59 【问题描述】:

我们有一个超过 62k 行的表。我们正在对其运行一个非常简单的删除查询,需要 45 分钟才能完成:

DELETE FROM myTable WHERE createdtime < '2017-03-07 05:00:00.000'

我们尝试过的事情:

1- 在时间戳列上添加了一个索引,但没有帮助。

2- 使用函数分批删除 20 或 50 行,这仍然非常慢。

3- 删除了引用此表的所有外键约束及其自己的主键约束,这确实有所帮助并将时间缩短到几秒钟,但我们无法在生产数据库上安全地执行此操作,因为它会锁定表并防止在事务运行时进行读写。

我不相信这个查询需要这么长时间才能完成是正常的。任何建议表示赞赏。

【问题讨论】:

Dropped all the foreign key constraints referencing this table 这些 FK 是否有支持它们的索引(在 other 表上)? 他说了什么。显然,时间花在查找 FK 约束上 性能问题应该包括 EXPLAIN ANALYZE 和一些关于表大小、索引、当前时间性能、期望时间等的信息。慢是一个相对术语,我们需要一个真正的值来比较。 mysql 也请阅读How-to-Ask @joop 我不敢相信我自己没有想到这一点!请添加它作为答案,以便我可以将其标记为已解决,因为这解决了问题。谢谢! 【参考方案1】:

... Dropped all the foreign key constraints referencing this table

确保这些 FK 具有支持它们的索引(在另一张表上)。 删除时,(级联)FK 必须检查其他表中可能引用该行的所有 FK 列。


-- 例子:

CREATE TABLE team(
        id INTEGER NOT NULL PRIMARY KEY
        , name varchar UNIQUE
        );

CREATE TABLE player(
        id INTEGER NOT NULL PRIMARY KEY
        , team_id integer REFERENCES team(id)
        , name varchar UNIQUE
        );

现在,如果team 被删除,FK 约束将不得不检查是否有任何玩家引用了这个team_id。 (并适当地级联) 在这种情况下,FK 上的支持性索引将有助于 DBMS:

CREATE index ON player(team_id);

将有所帮助在这里有点太弱了。对于每个重要的案例,绝对需要一个支持性索引。 (即使 FK 约束将 ON UPDATE NO ACTION ON DELETE NO ACTION 作为其 action,看起来也是如此)

【讨论】:

只是为了每个人的利益,即使我的 FK 都设置为 ON UPDATE NO ACTION ON DELETE NO ACTION,这个检查似乎无论如何都发生了,导致查询运行缓慢,这让我感到惊讶。 @infiniteLoop: 这一点都不奇怪,因为数据库需要确保周围没有玩家引用您要删除的team。如果没有索引,则该查找基本上是使用select * from player where team_id = ... 完成的,这将需要对播放器表进行 Seq Scan。 @a_horse_with_no_name: 但是为什么它需要检查它是否不打算删除与被删除的父行关联的子行? @infiniteLoop 因为需要防止有子行时删除父项 @infiniteLoop: 没有那个条件决定应该采取什么行动如果子行存在 - 但是子行的测试必须在如果存在外键

以上是关于Postgres 运行缓慢的删除查询的主要内容,如果未能解决你的问题,请参考以下文章

Postgres 进程显示 100% CPU 但实际使用率为 6%,导致查询响应缓慢

Postgres 选择查询在使用 JDBC 时运行缓慢,但在从同一服务器在 PSQL 中运行时快速

防止在 Postgres 中为特定查询使用索引

在 postgres 上缓慢选择不同的查询

最佳实践:优化Postgres查询性能(上)

最佳实践:优化Postgres查询性能(上)