函数扫描导致大量缓冲区命中并降低查询性能

时间:2021-06-11 16:09:25

标签: postgresql amazon-rds plpgsql

我正在尝试为利用 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 的复合索引。

任何想法或见解将不胜感激!

1 个答案:

答案 0 :(得分:2)

注意:从 RETURN QUERY 执行查询可能与直接运行查询不同。 Postgres 引擎可以使用通用计划而不是自定义计划,并且查询可能很慢。

您可以尝试改用 RETURN QUERY EXECUTE 语句。此语句始终强制自定义计划(另一方面,重新计划会产生开销)。

第二个注意事项:您的函数返回一行。如果这是您的函数的典型情况,您应该减少函数的属性 ROWS(默认值为 1000)。

最后一点:我不喜欢只是一个查询的信封的函数。通常这是反模式。 plpgsql 函数是用于优化的黑盒(当函数用于某些复杂查询时)。所以最好使用视图(如果可能的话)。

相关问题