ROLLUP小计行按GROUP BY列从左到右前缀组合逐级上卷生成,如GROUP BY a,b,c产生(a,b,c)→(a,b,NULL)→(a,NULL,NULL)→(NULL,NULL,NULL)四层;用GROUPING()函数区分真实NULL与小计占位符。

ROLLUP 生成的小计行到底按什么顺序出现?
MySQL 的 ROLLUP 不是简单叠加小计,而是按 GROUP BY 列的**从左到右前缀组合**逐级上卷。比如 GROUP BY a, b, c WITH ROLLUP 会生成:(a,b,c) → (a,b,NULL) → (a,NULL,NULL) → (NULL,NULL,NULL) 四层结果,最后一行是总计。注意:中间层级的 NULL 是 MySQL 标识小计行的标记,不是原始数据里的空值。
常见错误是误以为 ROLLUP 会自动补全“部门-城市”小计但漏掉“部门”小计——其实只要写了 GROUP BY dept, city,就一定先有 dept+city 组合,再有 dept 小计(city 为 NULL),最后才是全表总计(dept 和 city 都为 NULL)。
如何区分真实 NULL 和 ROLLUP 生成的 NULL?
直接查 city IS NULL 会把原始数据中城市为空的记录和小计行混在一起。必须用 GROUPING() 函数——它是 MySQL 8.0+ 专为 ROLLUP/CUBE 设计的判断工具。
-
GROUPING(city)返回 1 表示该行的city是ROLLUP生成的占位符,不是真实数据 -
GROUPING(dept)同理,可组合使用:GROUPING(dept) = 1 AND GROUPING(city) = 0表示这是“按城市汇总的总计行”(即 dept 小计缺失,但 city 有效) - 别用
IFNULL(city, '小计')这类写法替代,它无法区分场景,且会污染排序和索引下推
ORDER BY 和 ROLLUP 能一起用吗?
能,但顺序很关键:必须在 GROUP BY ... WITH ROLLUP 之后写 ORDER BY,且排序字段要兼容小计行的 NULL 值逻辑。默认情况下,NULL 在升序中排最前,容易让小计行跑到结果顶部,不符合阅读习惯。
实操建议:
- 用
ORDER BY dept IS NULL, dept, city IS NULL, city把小计行压到底部 - 避免对聚合字段(如
SUM(sales))单独排序,会导致小计行位置不可控 - 如果用
WITH ROLLUP后接LIMIT,MySQL 会先算完所有分组+小计再截断,可能意外丢掉总计行
ROLLUP 性能比普通 GROUP BY 差多少?
开销主要来自多一层分组计算和额外的内存暂存。在千万级表上,GROUP BY a,b WITH ROLLUP 比 GROUP BY a,b 多出约 15–25% 执行时间,但远低于手动 UNION ALL 拼多个 GROUP BY 的方案(后者 I/O 和解析开销翻倍)。真正要注意的是:如果 GROUP BY 字段没走索引,ROLLUP 会强制触发临时表 + 文件排序,此时加复合索引 (a,b) 能直接消除性能落差。
另外,ROLLUP 不支持下推到存储引擎层,所以带复杂 WHERE 条件时,务必确保过滤条件尽可能早地缩小数据集,否则小计计算量会随扫描行数线性增长。
多维度小计看着整齐,但每一层 NULL 都对应一次分组重算——别为了“看起来完整”而在高基数字段(比如用户 ID)上滥用 ROLLUP。


















