在group by之后添加rollup其实就是为分组以后的小组进行数据统计,当针对一个字段分组的时候则统计一次,如果是针对多个字段进行的分组那么最后需要针对每一个分组进行一次统计。
这里要注意一点,当使用rollup的时候就不能使用order by进行排序,换句话说 rollup和order by是相互排斥的。
实例如下:
rollup 是根据维度在数据结果集中进行的聚合操作。
假设用户需要对N个唯独进行聚合查询操作,普通的group by语句需要N个查询和N次group by操作。
而rollup的有点是一次可以去的N次group by的结果,这样可以提高查询效率,同时大大减少网络的传输流量。
(注,此表的表结构和数据与格式化聚合表formatting一致)
- CREATE TABLE rollup(
- orderid int NOT NULL,
- orderdate date NOT NULL,
- empid int NOT NULL,
- custid varchar(10) NOT NULL,
- qty int NOT NULL,
- PRIMARY KEY(orderid,orderdate));
- INSERT INTO rollup SELECT 1,'2010-01-02',3,'A',10;
- INSERT INTO rollup SELECT 2,'2010-04-02',2,'B',20;
- INSERT INTO rollup SELECT 3,'2010-05-02',1,'A',30;
- INSERT INTO rollup SELECT 4,'2010-07-02',3,'D',40;
- INSERT INTO rollup SELECT 5,'2011-01-02',4,'A',20;
- INSERT INTO rollup SELECT 6,'2011-01-02',3,'B',30;
- INSERT INTO rollup SELECT 7,'2011-01-02',1,'C',40;
- INSERT INTO rollup SELECT 8,'2009-01-02',2,'A',10;
- INSERT INTO rollup SELECT 9,'2009-01-02',3,'B',20;
首先做一个简单的一维聚合
- SELECT YEAR(orderdate) year,
- SUM(qty) sum
- FROM rollup
- GROUP BY YEAR(orderdate)
- WITH ROLLUP;
结果为
和普通的group by差别不大,只是多了一个(null,220),表示对所有的year再做一次聚合,即订单数量总和。
对单个唯独进行rollip操作只是可以在最后得到聚合的数据,对比group by语句并没有非常大的优势。
对多个维度进行rollup才能体现出rollup的优势:
(对3列进行层次的维度操作)
- SELECT empid, custid,
- YEAR(orderdate) year,
- SUM(qty) sum
- FROM rollup
- GROUP BY empid,custid,YEAR(orderdate)
- WITH ROLLUP;
结果为
其中(null,null,null)表示最后的聚合
(empid,custid,year)表示对这3列进行分组的聚合结果
(empid,custid,null)表示对(empid,custid)两列进行分组的聚合结果
(empid,null,null)表示仅对(empid)一列进行分组的聚合结果
所以上述语句等同于(但未排序)
- SELECT empid, custid, YEAR(orderdate) YEAR, SUM(qty) sum FROM rollup
- GROUP BY empid, custid, YEAR(orderdate)
- UNION
- SELECT empid, custid, NULL, SUM(qty) sum FROM rollup
- GROUP BY empid, custid
- UNION
- SELECT empid, NULL, NULL, SUM(qty) sum FROM rollup
- GROUP BY empid
- UNION
- SELECT NULL, NULL, NULL, SUM(qty) sum FROM rollup
虽然两者得到相同的结果,但是执行计划却不同
rollup只需要一次表扫描操作就能得到全部结果,因此查询效率在此得到了极大的提升。
P.S.
在使用rollup需要注意以下几方面
1.
ORDER BY不能在rollup中使用,两者为互斥关键字,如果使用,会抛出以下错误:
Error Code:1221. Incorrect usage of CUBE/ROLLUP and ORDER BY
2.
可以使用LIMIT,但是因为不能使用order by,所以阅读性下降,故大多数情况下无实际意义。
3.
如果分组的列包含NULL值,那么rollup的结果可能不正确
因为在rollup中进行的分组统计时,null具有特殊意义
因此在进行rollup时可以先将null转换成一个不可能存在的值,或者没有特别含义的值,比如:
IFNULL(xxx,0)
【关于cube】
rollup是cube的一种特殊情况,和rollup一样,cube也是一种对数据的聚合操作
但是rollup只在层次上对数据进行聚合,而cube对所有的维度进行聚合
具有N个维度的列,cube需要2的N次方次分组操作,而rollup只需要N次分组操作
在mysql 5.6.17版本中,只定义了cube,但是不支持cube操作:
- SELECT empid, custid, YEAR(orderdate), SUM(qty)
- FROM rollup
- GROUP BY empid, custid, YEAR(orderdate)
- WITH CUBE;
-- ERROR 1235 (42000): This version of MySQL doesn't yet support 'CUBE'
可以通过rollup来模拟cube:
- SELECT
- empid, custid, YEAR(orderdate) year, SUM(qty) sum from rollup
- GROUP BY empid, custid, YEAR(orderdate)
- WITH ROLLUP
- UNION
- SELECT
- empid, custid, YEAR(orderdate) year, SUM(qty) sum from rollup
- GROUP BY empid, YEAR(orderdate), custid
- WITH ROLLUP
- UNION
- SELECT
- empid, custid, YEAR(orderdate) year, SUM(qty) sum from rollup
- GROUP BY custid, YEAR(orderdate),empid
- WITH ROLLUP
- UNION
- SELECT
- empid, custid, YEAR(orderdate) year, SUM(qty) sum from rollup
- GROUP BY custid, empid, YEAR(orderdate)
- WITH ROLLUP
- UNION
- SELECT
- empid,custid,YEAR(orderdate) year, SUM(qty) sum from rollup
- GROUP BY YEAR(orderdate), empid, custid
- WITH ROLLUP
- UNION
- SELECT
- empid,custid,YEAR(orderdate) year, SUM(qty) sum from rollup
- GROUP BY YEAR(orderdate), custid, empid
- WITH ROLLUP;
产生的最终结果为: