Sql 子查询使用函数更快

Sql 子查询使用函数更快,sql,postgresql,postgresql-9.3,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) 无论是直接运行查询还是函数,我都会得到类似的结果和性能。到目前为止还不错 现在我有另一个长查询,它看

我在函数中嵌入了一个长查询(~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毫秒的速度运行,虽然速度很慢,但在这个阶段足够快(考虑到行数和聚合操作,这可能是有意义的)

但是,如果我用等价查询替换即期汇率(货币“USD”,当前日期),它将在5秒以上的时间内运行

无论我使用函数还是等效查询,单独运行子查询都会在大约200毫秒内返回

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

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


编辑:解释分析在2个子查询和整个查询上运行

  • 具有以下功能的子查询:
  • 直接查询的子查询:
  • 带功能的整体查询:
  • 整体查询与直接查询:
  • 仅函数体,使用一组参数:

只是一个猜测:您的查询的范围表超出了连接\u折叠\u限制,导致使用了次优计划


  • 尝试将子查询体(相当于函数)移动到CTE中,以保持其完整性。(始终执行CTE,并且查询生成器/计划器从不分解CTE)

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

  • 您可以(暂时)增加
    join\u collapse\u limit
    ,但这将花费更多的计划时间,这当然是有限制的(可能的计划数量随着范围表的大小呈指数增长)
  • 通常,您可以通过错误的查询计划来检测这种行为(比如这里:更少的索引扫描),但是您需要了解模式,并且必须有某种合理的计划(阅读:PK/FK,索引也必须正确)

spot_rate
function
VOLATILE
稳定的
不可变的
?@茄子我不认为它们中的任何一个-它是这样声明的:
创建或替换函数spot_rate(args)返回数值(20,8)作为$$SELECT xxx$$LANGUAGE SQL您可以使用pgAdmin在对象浏览器中单击函数名并查看SQL窗格中的定义,轻松地检查这一点。无论如何,如果您没有指定任何,PostgreSQL将假定
VOLATILE
。如果您将其定义为“稳定”或“不可变”
,那么您的问题的答案很容易猜到,但既然您没有这样做,它看起来确实违反直觉,人们可能会期望相反的结果。您不是第一个问这样的问题的人: