历史上,SQL中的聚合和分组任务常常用于生成报告和分析。在20世纪80年代的关系数据库管理系统中,出现了基本的聚合函数(SUM、COUNT、AVG),但在处理大量数据时,经典的GROUP BY会变得缓慢。出现了可扩展性的问题:带有数千万条记录和多个组的查询会锁定表并降低性能。
问题在于,使用不高效的方法时,SQL服务器在排序、临时表和磁盘读取上消耗了大量资源。当按照多个列进行分组或使用动态聚合数据集时,问题尤其严重。
解决方案在于正确构建分组列的索引、使用分区、“半聚合”和优化查询结构。对于业务分析任务,通常使用结构化的公用表表达式(CTE)、物化视图和窗口函数。
代码示例:
WITH PreAgg AS ( SELECT customer_id, region, SUM(amount) AS total_amount FROM sales WHERE sale_date >= '2024-01-01' GROUP BY customer_id, region ) SELECT region, COUNT(DISTINCT customer_id) AS customers, SUM(total_amount) AS region_amount FROM PreAgg GROUP BY region ORDER BY region_amount DESC;
关键特点:
GROUP BY的性能是否依赖于SELECT中列的顺序?
不,SELECT中列的顺序不影响速度,关键在于使用哪些列进行分组以及是否有索引。
在GROUP BY中,是否必须为SELECT中的每个字段指定聚合函数?
不一定,如果字段包含在GROUP BY中,可以直接输出而不进行聚合。如果字段不参与分组,则必须进行聚合。
SELECT department, MIN(salary) FROM employees GROUP BY department;
可以将一个GROUP BY嵌套在另一个GROUP BY中以进行多层次聚合吗?
可以,嵌套的CTE或子查询允许进行“多层次”的聚合并生成中间结果。
WITH Step1 AS ( SELECT customer, SUM(amount) AS cust_sum FROM orders GROUP BY customer ) SELECT COUNT(*) FROM Step1 WHERE cust_sum > 10000;
分析师在一个没有索引且没有样本划分的2亿条记录的表上构建包含多个GROUP BY的报告,整个办公室在早上9点"卡住"。执行耗时40分钟。
优点:
缺点:
工程师使用CTE进行初步过滤,在必要字段上建立合理的索引,并将聚合分成多个阶段。报告生成耗时5秒。
优点:
缺点: