sql - Postgres : If we select a computed column multiple times, Postgres会一次又一次地计算它吗?

标签 sql arrays postgresql join lateral-join

这是我正在尝试的查询,

SELECT s.id, s.name AS name,
CASE WHEN (ARRAY_AGG(tgs.status) @> '{Hard} ') THEN 'Hard'
WHEN (ARRAY_AGG(tgs.status) @> '{Soft} ') THEN 'Soft'
WHEN (ARRAY_AGG(tgs.status) @> '{Fluid} ') THEN 'Fluid'
WHEN (ARRAY_AGG(tgs.status) @> '{Gummy} ') THEN 'Gummy'
WHEN (ARRAY_AGG(tgs.status) @> '{Expired} ') THEN 'Expired'
END AS status, 
COUNT(*) OVER()
FROM sweets AS s 
INNER JOIN tasty_goofy_sweets AS tgs on tgs.sweet_id = s.id
GROUP BY s.id;

在实现这一点时,我的 friend 建议,我们可以使用 LEFT JOIN LATERAL 并只计算一次,而不是每次在 switch 情况下都计算 array_agg 。 即)像下面一样实现

SELECT s.id, s.name AS name,
CASE WHEN (tgs.status @> '{Hard} ') THEN 'Hard'
WHEN (tgs.arr_status @> '{Soft} ') THEN 'Soft'
WHEN (tgs.arr_status @> '{Fluid} ') THEN 'Fluid'
WHEN (tgs.arr_status @> '{Gummy} ') THEN 'Gummy'
WHEN (tgs.arr_status @> '{Expired} ') THEN 'Expired'
END AS status, 
COUNT(*) OVER()
FROM sweets AS s 
LEFT JOIN LATERAL ( SELECT ARRAY_AGG(tgs.status) AS arr_status FROM tasty_goofy_sweets tgs WHERE  tgs.sweet_id = s.id
) AS tgs ON TRUE
GROUP BY s.id;

但我不确定 Postgres 是否每次都会计算 ARRAY_AGG 值,我们如何确定哪种方法更好?我尝试查看这两个查询的解释分析,后一个查询涉及的行数比前者多。但我不明白为什么会这样?

我直觉地觉得前一种方法更好,但是有人可以推理出哪种方法更好吗?为什么或者我要求太多了?

最佳答案

Postgres 最有可能会优化掉多个 array_agg(),仅计算一次并在每次比较中重用结果。这是非常简单的查询优化,数据库应该很容易发现。

不过,我建议通过使用条件聚合来简化查询。您不需要聚合到数组中只是为了检查给定值是否存在:

select
    s.id,
    s.name
    case 
        when count(*) filter(where status = 'Hard')    > 0 then 'Hard',
        when count(*) filter(where status = 'Soft')    > 0 then 'Soft',
        when count(*) filter(where status = 'Fluid')   > 0 then 'Fluid'
        when count(*) filter(where status = 'Gummy')   > 0 then 'Gummy',
        when count(*) filter(where status = 'Expired') > 0 then 'Expired'
    end status,
    count(*) over() cnt
from sweets s
inner join tasty_goofy_sweets AS tgs on tgs.sweet_id = s.id
group by s.id;

您也可以使用横向连接和条件排序来表达这一点,而无需聚合:

select
    s.id,
    s.name,
    tgs.status,
    count(*) over() cnt
from sweets s
cross join lateral (
    select status
    from tasty_goofy_sweets as tgs 
    where tgs.sweet_id = s.id
    order by case status 
        when 'Hard'    then 1
        when 'Soft'    then 2
        when 'Fluid'   then 3
        when 'Gummy'   then 4
        when 'Expired' then 5
    end
    limit 1
) tgs

关于sql - Postgres : If we select a computed column multiple times, Postgres会一次又一次地计算它吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62375744/

相关文章:

PHP:变量(数组)是函数吗?

spring - 使用 Spring、Hibernate 和 C3P0 管理 Multi-Tenancy Web 应用程序中的连接池

ruby-on-rails - ActiveRecord 列无法自动转换为数字类型

mysql - 做两个 SELECT 查询,第二个查询依赖于第一个,第二个的结果连接在一个中

MYSQL 过滤彼此相邻的相同行

javascript - 将数据从一张纸过滤到另一张纸

java - 将 JTextField 转换为 int 数组(有异常(exception))

php - 具有 Symfony 3/Doctrine 属性形式的一对多对一

java - Apache Derby : SQLSyntaxErrorException

mysql - 将2行合并为一行,使用2列MYSQL