子查询使用函数更快

时间:2015-05-08 12:44:24

标签: sql postgresql postgresql-9.3

我有一个很长的查询(~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秒内运行。

无论是使用函数还是等效查询,单独运行子查询都会在〜200ms内返回。

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

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

编辑:EXPLAIN ANALYZE在2个子查询和整个查询上运行

1 个答案:

答案 0 :(得分:2)

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

  • 尝试将子查询体(相当于函数)移动到CTE中,以保持其完好无损。 (CTE总是被执行,并且永远不会被查询生成器/计划者分解)

  • 将查询中的部分预先分析到(TEMP)表或物化视图中也可以帮助减少RTE的数量

  • 可以(暂时)增加join_collapse_limit,但这会花费更多的计划时间,而且肯定有一个限制(可能的计划数量随着规模的增长呈指数级增长范围表。)
  • 通常情况下,您可以通过错误的查询计划检测此行为(例如:更少的索引扫描),但您需要了解架构,并且必须有某种合理的计划(读取:PK / FK和索引也必须正确)