问题描述
WITH USAGE AS NOT MATERIALIZED ( SELECT
ocd.*,1 AS conf_suma
FROM(
SELECT o,o.agreement_id AS agreement_id
FROM "order_bt" o
WHERE o.sys_period @> sys_time()
AND (o.app_period && tstzrange( '2021-01-01','2021-02-01' ))
)ocd
)
SELECT
*,(conf_suma/6) ::numeric( 10,2 ) as group_nds,(SELECT sum(conf_suma) from USAGE sq WHERE sq.agreement_id = agreement_id) as total_suma -- #1 SLOW
-- #2 FAST: (SELECT sum(conf_suma) from USAGE sq WHERE sq.agreement_id = 3385) as total_suma
FROM USAGE
WHERE agreement_id = 3385 -- LAST WHERE
它们的区别仅在于 sq.agreement_id = agreement_id
VS sq.agreement_id = 3385
为什么在第一种情况下不应用优化?在我看来,优化器可以从 LAST WHERE
看到只有一个 agreement_id
。所以 agreement_id
就像常数。如果我们将此常量折叠到 slow
子查询中,它就会与 fast
子查询相同。这是规划人员改进的地方吗?
附注。在我对生产的查询中,这导致查询运行 12 秒而不是 20 毫秒
解决方法
感谢 IRC 的 RhodiumToad。错误出在 agreement_id
名称上。
它必须写为 usage.agreement_id
:
(SELECT sum(conf_suma) from USAGE sq WHERE sq.agreement_id = usage.agreement_id) as total_suma -- #1 NOW IT IS FAST TOO
现在plan很好。正如我所期望的:
,因为查询速度慢,聚合函数对所有满足条件 sq.agreement_id = agreement_id
的行运行,即 1346 行,然后过滤子查询的结果
而快速查询立即过滤结果,子查询仅返回 4 行,因此仅聚合仅运行 4 行。
此外,如果您查看 #4 Bitmap Index Scan 的索引条件,由于您的条件,sql 优化器必须查找这些条件:
((o_1.sys_period @> sys_time())
AND (o_1.app_period && '["2021-01-01 00:00:00+02","2021-02-01 00:00:00+02")'::tstzrange))
在快速查询中,索引条件为
(o_1.agreement_id = 3385)
所以慢查询中的那些条件被推迟到 #3 Bitmap Heap Scan
只适用于快速查询的 4 行。