从表中提高SQL更新的性能

时间:2014-09-25 21:29:42

标签: sql postgresql postgresql-9.3

我正在运行如下的查询

update foo f set type=b.type from bar b where f.bar_id = b.id;

这些表中的每一个都有数百万行。我觉得奇怪的是对此查询进行分析表明它运行了2次表扫描,而不是使用它加入bar主键的事实。

有关如何使用索引或以其他方式提高速度的任何想法?

2 个答案:

答案 0 :(得分:0)

PostgreSQL在处理这种声明方面做得不好。问题在于,它几乎就像是一个选择查询而花费它们,忽略了它现在必须访问foo的每个限定行以对其进行更改的事实。因此,如果它选择一个查询路径,该路径返回物理顺序中的foo行,这几乎是除了以下所有查询路径:

nested loop
    seq scan on foo
    index scan on bar

然后它会跳过所有的tarnation试图更新foo的行不按顺序。

如果它确实选择了上述计划,那么它现在正在跳过bar读取该故障。但跳过遍布脏页的情况通常比跳过阅读页面更糟糕,而不会弄脏它们。

您最好的选择可能只是使用CREATE TABLE ... AS SELECT重新创建foo2 ... 然后重命名。如果有很多外键约束和视图引用foo,那可能会很痛苦。

如果您有RAM,可以尝试将work_mem提升到单程计划的程度:

hash join
    seq scan on foo
    hash
        seq scan on bar

但是如果它决定它需要在多次通过中进行,因为它不适合记忆,那么当你回到随机跳跃时,事情就会匆匆走向南方。更糟糕的是,PostgreSQL在计划这一点时毫无帮助,而且你很可能会得到

hash join
    seq scan on bar
    hash
        seq scan on foo

这是一个可怕的计划。

答案 1 :(得分:0)

在您的情况下考虑事务日志压力。也许你可以将事务分成几个,每行50k行?

此外,如果更新> 1m行,我建议您在UPDATE之前更改除WHERE子句之外的所有索引到INACTIVE状态。