CUBE是GROUP BY的扩展,用于自动生成所有维度组合的聚合结果,等价于显式列举全部GROUPING SETS;它产生2ⁿ组结果(n为列数),需配合GROUPING()函数区分汇总NULL与原始NULL。

什么是CUBE,它和GROUPING SETS有什么关系
CUBE不是独立的聚合语法,而是GROUP BY子句的扩展选项,用于自动生成所有可能的维度组合汇总。它的行为等价于显式写出全部GROUPING SETS——比如GROUP BY CUBE(a, b, c)等价于GROUP BY GROUPING SETS ((a,b,c), (a,b), (a,c), (b,c), (a), (b), (c), ())。这意味着它会产出 2ⁿ 行结果(n 是列数),包括全表总计(空元组)。
实际使用中,CUBE 更简洁,但代价是无法控制组合顺序或跳过某些维度组合;如果只需要部分交叉汇总,直接写GROUPING SETS更精准、也更容易被优化器识别。
怎么写一个带CUBE的SELECT,注意NULL和GROUPING()函数
CUBE 会在缺失维度的汇总行中把对应列设为NULL,但这和原始数据里的NULL无法区分。必须用GROUPING()函数判断:当GROUPING(col) = 1时,表示该行是因CUBE生成的汇总行,col被“折叠”了。
-
SELECT COALESCE(region, 'ALL_REGIONS') AS region, COALESCE(product, 'ALL_PRODUCTS') AS product, SUM(sales) FROM sales GROUP BY CUBE(region, product)—— 这样写会混淆真实NULL值和汇总占位符 - 正确做法是:
SELECT CASE WHEN GROUPING(region)=1 THEN 'ALL_REGIONS' ELSE region END AS region, CASE WHEN GROUPING(product)=1 THEN 'ALL_PRODUCTS' ELSE product END AS product, SUM(sales) FROM sales GROUP BY CUBE(region, product) - MySQL 8.0+、PostgreSQL 14+、SQL Server 都支持CUBE;但 SQLite 和旧版 PostgreSQL 不支持,需改用
UNION ALL模拟
CUBE性能差得离谱?哪些情况要特别小心
CUBE 的计算量随维度数指数增长,3 列产生 8 组,5 列就是 32 组,10 列就到 1024 组——不只是结果行多,中间聚合过程也可能反复扫描数据或构建大哈希表。
- 避免对高基数列(如
user_id、order_id)用CUBE,哪怕只加一列,性能可能断崖下跌 - 如果只是想查“每个地区每个产品的销售额 + 各地区小计 + 总计”,用
ROLLUP(region, product)更合适,它只生成嵌套层级(region+product → region → total),不生成 product 单独的小计 - 在WHERE里提前过滤数据(比如限定
WHERE year = 2023)比在CUBE后用HAVING过滤更高效,因为能减少输入行数
为什么执行计划里看不到CUBE,却看到大量HashAggregate
数据库引擎不会保留CUBE这个逻辑节点,而是在查询重写阶段就把它展开成多个分组路径,再合并。所以执行计划中通常只看到HashAggregate或GroupAggregate,且Node中常有“multiple grouping sets”字样(PostgreSQL)或“Compute Scalar + Hash Match”组合(SQL Server)。
这意味着你不能靠“有没有CUBE字样”来判断是否生效;验证方式只有两个:EXPLAIN看输出行数是否接近 2ⁿ × 基础分组数,以及检查结果里是否存在GROUPING()返回 1 的行。漏掉GROUPING()处理,上线后报表里的“ALL_XXX”就可能被当成脏数据误删。










