sql - Postgres:如果我们多次选择一个计算列,Postgres 会一次又一次地计算它吗?
问题描述
这是我正在尝试的查询,
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;
在实现这一点时,我的朋友建议,我们可以使用 LEFT JOIN LATERAL 并只计算一次,而不是每次在 switch case 中计算 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
每次都计算该值,我们如何确定哪种方法更好?我尝试查看explain analyse
这两个查询,后者查询中涉及的行数比前者多。但我不明白为什么会这样?
我凭直觉觉得前一种方法更好,但是有人可以解释一下,哪种更好,为什么还是我要求太多?
解决方案
最有可能的是,Postgres 会优化掉多个array_agg()
s,只计算一次并在每次比较中重用结果。这是非常简单的查询优化,数据库应该很容易发现。
但是,让我建议通过使用条件聚合来简化查询。哟不需要聚合成一个数组只是为了检查给定的值是否存在:
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
推荐阅读
- python - 我无法安装 install firebase-admin
- java - 多个复选框值到弹簧控制器
- ios - 如何将 addTarget 与标签、imageview 或 uiview 一起使用?
- python - Python if 条件简化
- google-apps-script - 如何从插件中获取谷歌应用脚本中活动页面的 DOM 元素
- google-cloud-platform - 如何在 GCE 实例上清理与 SSH 元数据关联的用户?
- git - 使用 git bash 时权限被拒绝
- amazon-web-services - 当两个 DynamoDB 表都具有按需容量时,如何使用 Data Pipeline 将数据复制到另一个 DynamoDB 表
- javascript - 三元运算符如何比较 JavaScript 中的字符和数字?
- php - 由于“字符串”导致错误的字段 INTO OUTFILE mysql