使用函数子查询更快
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 运行
- 带有函数的子查询:http://explain.depesz.com/s/UHCF
- 带直接查询的子查询:http://explain.depesz.com/s/q5Q
- 整个查询函数:http://explain.depesz.com/s/ZDt
- 带直接查询的整个查询:http://explain.depesz.com/s/R2f
- 只是函数体,使用一组参数:http://explain.depesz.com/s/mEp
只是一个大胆的猜测:您的查询范围 table 超出了 join_collapse_limit,导致使用了次优计划。
尝试将子查询主体(相当于函数)移动到 CTE 中,以保持其完整。 (CTE 总是被执行,并且永远不会被 query-generator/planner 分解)
将部分查询预计算到 (TEMP) table 或实体化视图中也有助于减少 RTE 的数量
- 你可以(暂时)增加
join_collapse_limit
,但这会花费更多的计划时间,而且这肯定有一个限制(可能的计划数量会增加随范围 table.) 的大小呈指数增长
- 通常,您可以通过糟糕的查询计划检测到此行为(如此处:更少的索引扫描),但您需要了解架构,并且必须有某种可能的合理计划(阅读:PK/FK 并且索引也必须正确)
我有一个很长的查询(约 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 运行
- 带有函数的子查询:http://explain.depesz.com/s/UHCF
- 带直接查询的子查询:http://explain.depesz.com/s/q5Q
- 整个查询函数:http://explain.depesz.com/s/ZDt
- 带直接查询的整个查询:http://explain.depesz.com/s/R2f
- 只是函数体,使用一组参数:http://explain.depesz.com/s/mEp
只是一个大胆的猜测:您的查询范围 table 超出了 join_collapse_limit,导致使用了次优计划。
尝试将子查询主体(相当于函数)移动到 CTE 中,以保持其完整。 (CTE 总是被执行,并且永远不会被 query-generator/planner 分解)
将部分查询预计算到 (TEMP) table 或实体化视图中也有助于减少 RTE 的数量
- 你可以(暂时)增加
join_collapse_limit
,但这会花费更多的计划时间,而且这肯定有一个限制(可能的计划数量会增加随范围 table.) 的大小呈指数增长
- 通常,您可以通过糟糕的查询计划检测到此行为(如此处:更少的索引扫描),但您需要了解架构,并且必须有某种可能的合理计划(阅读:PK/FK 并且索引也必须正确)