使用函数子查询更快

Subquery is faster using a function

我有一个很长的查询(约 200 行),我已将其嵌入函数中:

CREATE FUNCTION spot_rate(base_currency character(3),
                          contra_currency character(3),
                          pricing_date date) RETURNS numeric(20,8)

无论是 运行 直接查询还是函数,我都得到了相似的结果和相似的性能。到目前为止一切顺利。

现在我有另一个长查询,如下所示:

SELECT x, sum(y * spot_rates.spot)
FROM (SELECT a, b, sum(c) FROM t1 JOIN t2 etc. (6 joins here)) AS table_1,
     (SELECT
        currency,
        spot_rate(currency, 'USD', current_date) AS "spot"
      FROM (SELECT DISTINCT currency FROM table_2) AS "currencies"
     ) AS "spot_rates"
WHERE
     table_1.currency = spot_rates.currency
GROUP BY / ORDER BY

此查询 运行 秒用时 300 毫秒,速度较慢但在现阶段足够快(考虑到行数和聚合操作,这可能是有意义的)。

如果我用它的等效查询替换 spot_rate(currency, 'USD', current_date),它会在 5+ 秒内 运行s。

运行 单独的子查询 returns 在 ~200 毫秒内,无论我使用函数还是等效查询。

当用作子查询时,为什么查询 运行 比函数慢?

ps:我希望这个一般问题有一个通用的答案 - 如果没有,我会 post 更多细节,但创建一个人为的例子并不简单。


编辑:对 2 个子查询和整个查询进行 EXPLAIN ANALYZE 运行

只是一个大胆的猜测:您的查询范围 table 超出了 join_collapse_limit,导致使用了次优计划。


  • 尝试将子查询主体(相当于函数)移动到 CTE 中,以保持其完整。 (CTE 总是被执行,并且永远不会被 query-generator/planner 分解)

  • 将部分查询预计算到 (TEMP) table 或实体化视图中也有助于减少 RTE 的数量

  • 可以(暂时)增加join_collapse_limit,但这会花费更多的计划时间,而且这肯定有一个限制(可能的计划数量会增加随范围 table.)
  • 的大小呈指数增长
  • 通常,您可以通过糟糕的查询计划检测到此行为(如此处:更少的索引扫描),但您需要了解架构,并且必须有某种可能的合理计划(阅读:PK/FK 并且索引也必须正确)