我正在运行如下的查询
update foo f set type=b.type from bar b where f.bar_id = b.id;
这些表中的每一个都有数百万行。我觉得奇怪的是对此查询进行分析表明它运行了2次表扫描,而不是使用它加入bar
主键的事实。
有关如何使用索引或以其他方式提高速度的任何想法?
答案 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状态。