PostgreSQL 升级到 12+ 将散列连接更改为慢速嵌套循环
PostgreSQL upgrade to 12+ changes hash join to slow nested loop
我们正在尝试从版本 9 系列升级,并且有一个破坏交易的慢查询,它在 10 和 11 中运行正常,但在 12 和 13 中慢了很多倍。我在次要版本中进行了测试11、12系列,小版本不影响
问题在于规划器选择了嵌套循环连接而不是它应该使用的散列连接。
v11 哈希连接:
-> Nested Loop Left Join (cost=276056.74..285056.52 rows=1714 width=230) (actual time=13519.865..15864.542 rows=57 loops=1)
Join Filter: (placement_type.placement_type_id = job_order.placement_type_id)
Rows Removed by Join Filter: 57
-> Nested Loop Left Join (cost=276056.74..284967.78 rows=1714 width=224) (actual time=13519.837..15864.202 rows=57 loops=1)
-> Hash Join (cost=276056.32..284215.53 rows=1714 width=217) (actual time=13519.803..15863.465 rows=57 loops=1)
Hash Cond: (ori.order_id = job_order_1.order_id)
-> HashAggregate (cost=246953.68..250381.92 rows=342824 width=487) (actual time=13397.503..15017.114 rows=1053462 loops=1)
v12 嵌套循环:
-> Nested Loop Left Join (cost=304636.78..316645.32 rows=1716 width=230) (actual time=17799.135..152297.231 rows=57 loops=1)
Join Filter: (placement_type.placement_type_id = job_order.placement_type_id)
Rows Removed by Join Filter: 57
-> Nested Loop Left Join (cost=304636.78..316556.50 rows=1716 width=224) (actual time=17799.111..152296.749 rows=57 loops=1)
-> Nested Loop (cost=304636.37..315803.37 rows=1716 width=217) (actual time=17799.075..152295.098 rows=57 loops=1)
Join Filter: (job_order_1.order_id = ori.order_id)
Rows Removed by Join Filter: 60047277
我们测试环境中的升级过程是通过 pg_upgrade 完成的,并在测试此查询之前进行了全面分析。
那么 12 有什么变化?
感谢 PG 邮寄名单上的人,他们的回答值得称赞。
在 PostgreSQL12 之前,使用 CTE 创建了一个“优化障碍”。在某些情况下,幸运的是,这导致了查询的良好性能,否则,规划器无法成功估计。
添加 MATERIALIZED 关键字 (WITH ... AS MATERIALIZED (...)
) 强制执行旧行为。所以这是解决性能问题的一种方法。另一种方法是优化给规划器带来麻烦的 SQL,当规划器决定重新安排 CTE 的处理时,这可能会浮出水面。
我们正在尝试从版本 9 系列升级,并且有一个破坏交易的慢查询,它在 10 和 11 中运行正常,但在 12 和 13 中慢了很多倍。我在次要版本中进行了测试11、12系列,小版本不影响
问题在于规划器选择了嵌套循环连接而不是它应该使用的散列连接。
v11 哈希连接:
-> Nested Loop Left Join (cost=276056.74..285056.52 rows=1714 width=230) (actual time=13519.865..15864.542 rows=57 loops=1)
Join Filter: (placement_type.placement_type_id = job_order.placement_type_id)
Rows Removed by Join Filter: 57
-> Nested Loop Left Join (cost=276056.74..284967.78 rows=1714 width=224) (actual time=13519.837..15864.202 rows=57 loops=1)
-> Hash Join (cost=276056.32..284215.53 rows=1714 width=217) (actual time=13519.803..15863.465 rows=57 loops=1)
Hash Cond: (ori.order_id = job_order_1.order_id)
-> HashAggregate (cost=246953.68..250381.92 rows=342824 width=487) (actual time=13397.503..15017.114 rows=1053462 loops=1)
v12 嵌套循环:
-> Nested Loop Left Join (cost=304636.78..316645.32 rows=1716 width=230) (actual time=17799.135..152297.231 rows=57 loops=1)
Join Filter: (placement_type.placement_type_id = job_order.placement_type_id)
Rows Removed by Join Filter: 57
-> Nested Loop Left Join (cost=304636.78..316556.50 rows=1716 width=224) (actual time=17799.111..152296.749 rows=57 loops=1)
-> Nested Loop (cost=304636.37..315803.37 rows=1716 width=217) (actual time=17799.075..152295.098 rows=57 loops=1)
Join Filter: (job_order_1.order_id = ori.order_id)
Rows Removed by Join Filter: 60047277
我们测试环境中的升级过程是通过 pg_upgrade 完成的,并在测试此查询之前进行了全面分析。
那么 12 有什么变化?
感谢 PG 邮寄名单上的人,他们的回答值得称赞。
在 PostgreSQL12 之前,使用 CTE 创建了一个“优化障碍”。在某些情况下,幸运的是,这导致了查询的良好性能,否则,规划器无法成功估计。
添加 MATERIALIZED 关键字 (WITH ... AS MATERIALIZED (...)
) 强制执行旧行为。所以这是解决性能问题的一种方法。另一种方法是优化给规划器带来麻烦的 SQL,当规划器决定重新安排 CTE 的处理时,这可能会浮出水面。