为什么不应用优化/使用不同的索引?

问题描述

我有两个非常相似的查询

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#2 fast

#1 慢

enter image description here

#2 快

enter image description here

为什么在第一种情况下不应用优化?在我看来,优化器可以从 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很好。正如我所期望的: enter image description here

,

因为查询速度慢,聚合函数对所有满足条件 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 行。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...