SQL中的GROUPING SETS和ROLLUP都是用于实现多维聚合的语法,二者存在明确的等价转换关系,合理运用等价写法并优化可以大幅提升复杂统计查询的性能。

GROUPING SETS与ROLLUP的基础语法
ROLLUP是GROUPING SETS的简化写法,用于生成层级式的聚合结果。比如对维度a、b做ROLLUP,等价于指定多组聚合维度组合。以下是二者的基础语法示例:
-- ROLLUP基础写法
SELECT a, b, SUM(c) AS total
FROM test_table
GROUP BY ROLLUP(a, b);
-- 等价的GROUPING SETS写法
SELECT a, b, SUM(c) AS total
FROM test_table
GROUP BY GROUPING SETS(
(a, b), -- 同时聚合a和b
(a), -- 仅聚合a
() -- 全表聚合
);
ROLLUP转GROUPING SETS的等价规则
ROLLUP的维度列表有n个字段时,会生成n+1组聚合组合,对应GROUPING SETS的写法需要包含所有层级的组合:
- 第1组:所有n个维度都参与聚合
- 第2组:前n-1个维度参与聚合
- 以此类推,直到仅第1个维度参与聚合
- 最后一组:空组合,即全表聚合
比如3个维度的ROLLUP(a,b,c)等价于GROUPING SETS((a,b,c),(a,b),(a),()),可以通过如下代码验证结果一致性:
-- 3维度ROLLUP SELECT a, b, c, SUM(d) AS total FROM sales GROUP BY ROLLUP(a, b, c) ORDER BY a, b, c; -- 等价的GROUPING SETS SELECT a, b, c, SUM(d) AS total FROM sales GROUP BY GROUPING SETS((a,b,c),(a,b),(a),()) ORDER BY a, b, c;
等价写法的优化技巧
1. 减少不必要的聚合组合
如果业务中不需要全表聚合或者某层级的聚合结果,可以在转换GROUPING SETS时去掉对应组合,减少计算量。比如只需要(a,b,c)和(a,b)两层的聚合,就不需要写(a)和()的组合:
-- 优化后的GROUPING SETS,仅保留需要的聚合组合 SELECT a, b, c, SUM(d) AS total FROM sales GROUP BY GROUPING SETS((a,b,c),(a,b));
2. 配合GROUPING函数过滤结果
GROUPING函数可以判断某维度是否为聚合列,返回1表示当前行是该维度的聚合结果,0表示是原始分组值。可以用它过滤不需要的聚合行,减少返回数据量:
SELECT
a,
b,
c,
SUM(d) AS total,
GROUPING(a) AS is_a_agg,
GROUPING(b) AS is_b_agg,
GROUPING(c) AS is_c_agg
FROM sales
GROUP BY GROUPING SETS((a,b,c),(a,b),(a),())
-- 过滤掉全表聚合的行
HAVING GROUPING(a) = 0 OR GROUPING(b) = 0;
3. 索引优化
多维聚合查询的性能很大程度依赖索引,建议根据聚合维度的使用频率创建组合索引。比如常用的聚合组合是(a,b,c)和(a,b),可以创建索引idx_sales_a_b_c:
-- 创建组合索引优化聚合查询 CREATE INDEX idx_sales_a_b_c ON sales(a, b, c, d);
索引包含聚合用到的所有字段时,数据库可以直接使用索引完成聚合,避免全表扫描。
4. 执行计划分析
转换写法后可以通过EXPLAIN查看执行计划,确认是否使用了索引,是否存在不必要的排序操作。如果ROLLUP写法生成了额外的排序步骤,而GROUPING SETS写法可以避免,就可以选择后者提升性能。
-- 查看GROUPING SETS写法的执行计划 EXPLAIN SELECT a, b, c, SUM(d) AS total FROM sales GROUP BY GROUPING SETS((a,b,c),(a,b),(a),());
注意事项
不同数据库对GROUPING SETS和ROLLUP的支持略有差异,比如MySQL从8.0版本开始支持这两个语法,低版本无法使用。转换写法时需要先确认当前数据库版本是否兼容,避免语法错误。另外等价写法的结果顺序可能略有不同,如果需要固定顺序要额外加ORDER BY子句。
SQLGROUPING_SETSROLLUP多维聚合查询优化修改时间:2026-07-15 08:15:32