2

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

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_idVSsq.agreement_id = 3385

他们的计划是#1慢#2快

#1 慢 在此处输入图像描述

#2 快 在此处输入图像描述

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

PS。在我对生产的查询中,这导致查询运行 12 秒而不是 20 毫秒

4

2 回答 2

2

感谢 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

现在计划好。正如我所料: 在此处输入图像描述

于 2021-04-19T18:24:15.877 回答
0

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

于 2021-04-19T17:16:27.240 回答