为什么优化没有使用applied/different索引?

Why optimization is not applied/different index is used?

我有两个非常相似的查询:

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

他们的计划是#1 slow and #2 fast

#1 慢

#2快

为什么在第一种情况下不应用优化?在我看来,优化器可以从 LAST WHERE 中看出只有一个 agreement_id。所以 agreement_id 就像常数。如果我们将此常量折叠到 slow 子查询中,它将与 fast 子查询相同。这个地方是规划师改进的地方吗?

PS。在我对生产的一次查询中,这导致查询 运行 12sec 而不是 20ms

因为查询慢,聚合函数对所有满足条件sq.agreement_id = agreement_id的行运行,即1346行,然后过滤子查询的结果 虽然快速查询可以立即过滤结果,但子查询仅 returns 4 行,因此仅聚合仅运行 4 行。

如果您查看 #4 位图索引扫描的索引条件,由于您的条件 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 行。

感谢 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 很好。正如我所料: