【发布时间】:2014-01-16 03:17:21
【问题描述】:
在分析处理中,通常需要将“不重要”的数据组折叠到结果表中的单行中。一种方法是通过 CASE 表达式对不重要的组进行 GROUP BY,其中不重要的组通过返回单个值的 CASE 表达式合并为一行,例如,组为 NULL。这个问题是关于在 Amazon Redshift 中执行此分组的有效方法,它基于 ParAccel:在功能方面接近 PosgreSQL 8.0。
例如,考虑在表中的 type 和 url 上的 GROUP BY,其中每一行都是单个 URL 访问。目标是执行聚合,以便为 URL 访问计数超过某个阈值的每个 (type, url) 对发出一行,并为 all (type , url) 对,其中访问计数低于该阈值。结果表中的其余列将具有基于此分组的 SUM/COUNT 聚合。
比如下面的数据
+------+----------------------+-----------------------+
| type | url | < 50+ other columns > |
+------+----------------------+-----------------------+
| A | http://popular.com | |
| A | http://popular.com | |
| A | < 9997 more times> | |
| A | http://popular.com | |
| A | http://small-one.com | |
| B | http://tiny.com | |
| B | http://tiny-too.com | |
应该产生如下阈值为10000的结果表
+------+------------------------------------+--------------------------+
| type | url | visit_count | < SUM/COUNT aggregates > |
+------+------------------------------------+--------------------------+
| A | http://popular.com | 10000 | |
| A | | 1 | |
| B | | 2 | |
总结:
Amazon Redshift 有一定的子查询关联限制,需要小心谨慎。下面 Gordon Linoff 的回答(已接受的答案)展示了如何使用双重聚合执行 GROUP BY a CASE 表达式,并在结果列和外部 GROUP BY 子句中复制表达式。
with temp_counts as (SELECT type, url, COUNT(*) as cnt FROM t GROUP BY type, url)
select type, (case when cnt >= 10000 then url end) as url, sum(cnt) as cnt
from temp_counts
group by type, (case when cnt >= 10000 then url end)
进一步的测试表明,双重聚合可以“展开”成一个 UNION ALL 独立查询,涉及每个独立的 CASE 表达式。在这个具有大约 200M 行的样本数据集的特殊情况下,这种方法的执行速度始终快了大约 30%。但是,该结果是特定于模式和数据的。
with temp_counts as (SELECT type, url, COUNT(*) as cnt FROM t GROUP BY type, url)
select * from temp_counts WHERE cnt >= 10000
UNION ALL
SELECT type, NULL as url, SUM(cnt) as cnt from temp_counts
WHERE cnt < 10000
GROUP BY type
这表明了在 Amazon Redshift 中实施和优化任意脱节分组和汇总的两种通用模式。如果性能对您很重要,请对两者进行基准测试。
【问题讨论】:
标签: sql postgresql group-by amazon-redshift paraccel