为什么 Postgres 从 9.2.24 升级到 10.17 性能大幅下降?

Why is Postgres performance greatly reduced upgrading from 9.2.24 to 10.17?

问题

我有问题,SELECT p.* FROM parties p INNER JOIN bib b ON p.id=b.id;

在 Postgres 版本 9.2.24 上,此查询需要 12 或 13 分钟。这是 EXPLAIN ANALYZE 对上述查询的输出:

                                                                QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=156455.80..24854275.23 rows=4608791 width=46) (actual time=2516.474..407029.156 rows=4556073 loops=1)
   Hash Cond: (p.id = b.pid)
   ->  Seq Scan on parties p  (cost=0.00..22882138.64 rows=128697664 width=46) (actual time=371.099..220812.052 rows=133719944 loops=1)
   ->  Hash  (cost=98845.91..98845.91 rows=4608791 width=4) (actual time=2141.741..2141.741 rows=4608467 loops=1)
         Buckets: 524288  Batches: 1  Memory Usage: 162017kB
         ->  Seq Scan on bib b  (cost=0.00..98845.91 rows=4608791 width=4) (actual time=21.570..1199.429 rows=4608467 loops=1)
 Total runtime: 407293.833 ms
(7 rows)

在 Postgres 版本 10.17 上,此查询大约需要 3 小时。这是 EXPLAIN ANALYZE 对上述查询的输出:

                                                                           QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.57..12597544.56 rows=10945244 width=1038) (actual time=49.143..31536008.494 rows=10854924 loops=1)
   Workers Planned: 5
   Workers Launched: 5
   ->  Nested Loop  (cost=0.57..11502020.16 rows=2189049 width=1038) (actual time=88.401..31499828.808 rows=1809154 loops=6)
         ->  Parallel Seq Scan on bib b  (cost=0.00..147545.49 rows=2189049 width=4) (actual time=3.113..1830.876 rows=1824207 loops=6)
         ->  Index Scan using idx_parties_cmp on parties p  (cost=0.57..5.18 rows=1 width=1038) (actual time=17.262..17.265 rows=1 loops=10945244)
               Index Cond: (id = b.id)
 Planning time: 114.828 ms
 Execution time: 31536841.489 ms
(9 rows)

备注

问题

成本估算在 9.2 和 10 之间发生了变化,但变化不大(假设可配置设置没有发生根本变化——除非你告诉我们,否则我们无法知道这一点)。

最大的区别(在此处可能与您相关的那些区别中)是查询内并行化的引入,这当然需要更改成本模型。 v10 认为总成本将减少 2 倍,但它也认为将有 6 个进程专用于它,因此它认为总共将使用 3 倍多的资源。它可能没有从并行化中获得任何好处(因为您的硬件不足),但它错误地认为它会。

注意v10中max_parallel_workers_per_gather的默认设置是2,但是你明明运行至少是5的设置。换句话说,有人设置你的服务器显然是出了问题他们向 PostgreSQL 谎报服务器能力的方式。

现在显然这不是唯一的估计问题。如果我们说 return 两倍的数据需要 75 倍的时间,并且在并行化学分中原谅它 6 倍,那么它仍然错了大约 6 倍。但据我们所知,它是即使在 9.2 中也减少了这个数量。可能是 6 倍估计误差仍然使嵌套循环看起来更昂贵,所以没有选择它。只有当该错误与平行错误估计相结合时,组合错误才会变得足够高以改变计划。确切知道的方法是强制 9.2 使用嵌套循环计划,看看它实际慢了多少,以及它的预期成本是多少。当然,如果练习的目的是“我该如何解决这个问题”而不是“我应该为此责怪谁”,那么针对 9.2 进行这项工作可能毫无意义。