我正在尝试为利用 plpgsql 函数的 Postgres 查询诊断一些有问题的性能问题。
仅跨租户 ID 变化的完全相同的查询对于租户 A 比租户 B 慢 100 倍。有趣的是,租户 A 的数据明显少于租户 B,但仍需要两个数量级的时间才能完成。两个租户的查询计划和成本看起来相同,但读取的缓冲区数量也增加了 100 倍:
租户 A (ANALYZE, BUFFERS)
:
Aggregate (cost=42.68..42.69 rows=1 width=32) (actual time=9947.178..9947.179 rows=1 loops=1)
Buffers: shared hit=8412371
租户 B (ANALYZE, BUFFERS)
:
Aggregate (cost=42.68..42.69 rows=1 width=32) (actual time=149.142..149.143 rows=1 loops=1)
Buffers: shared hit=83373
进一步缩小范围,我可以隔离查询计划中的问题步骤:
-> Function Scan on a_plgpsql_function (cost=0.25..10.25 rows=1000 width=52) (actual time=3169.867..3169.868 rows=1 loops=3)
Buffers: shared hit=8412369
奇怪的是,如果我提取函数体(它是一个非常直接的参数化 RETURN QUERY
)并尝试在函数不作为图片的一部分的情况下复制问题,以便我可以获得更多细节查询计划我不再看到性能问题出现。
另一个有趣的上下文是,我从 RDS 集群中获取了数据库的完整 pg_dump 并将其加载到本地 Postgres 实例中,性能问题消失了,我看到租户 A 和租户 B 的性能相似。
>此时我有点超出我的深度,不确定是否应该开始考虑手动启动一些 VACUUM
操作,或者我是否应该考虑在某些操作上运行 CLUSTER
作为查询的一部分接触的表。我们确实有一些通常包含租户 ID 的复合索引。
任何想法或见解将不胜感激!
答案 0 :(得分:2)
注意:从 RETURN QUERY
执行查询可能与直接运行查询不同。 Postgres 引擎可以使用通用计划而不是自定义计划,并且查询可能很慢。
您可以尝试改用 RETURN QUERY EXECUTE
语句。此语句始终强制自定义计划(另一方面,重新计划会产生开销)。
第二个注意事项:您的函数返回一行。如果这是您的函数的典型情况,您应该减少函数的属性 ROWS
(默认值为 1000)。
最后一点:我不喜欢只是一个查询的信封的函数。通常这是反模式。 plpgsql 函数是用于优化的黑盒(当函数用于某些复杂查询时)。所以最好使用视图(如果可能的话)。