MySQL ROLLUP和CUBE區別


rollup 是根據維度在數據結果集中進行的聚合操作。
假設用戶需要對N個維度進行聚合查詢操作,普通的group by語句需要N個查詢和N次group by操作。
而rollup的優點是一次可以得出N次group by的結果,這樣可以提高查詢效率,同時大大減少網絡的傳輸流量。


如果是Group by  ROLLUP(A, B, C)的話,首先會對(A、B、C)進行GROUP BY,然後對(A、B)進行GROUP BY,然後是(A)進行GROUP BY,最後對全表進行GROUP BY操作。
如果是GROUP BY CUBE(A, B, C),則首先會對(A、B、C)進行GROUP BY,然後依次是(A、B),(A、C),(A),(B、C),(B),(C),最後對全表進行GROUP BY操作。 grouping_id()可以美化效果。除了使用GROUPING函數,還可以使用GROUPING_ID來標識GROUP BY的結果。


(注,此表的表結構和數據與格式化聚合表formatting一致)

  1. CREATE TABLE rollup(

  2. orderid int NOT NULL,

  3. orderdate date NOT NULL,

  4. empid int NOT NULL,

  5. custid varchar(10) NOT NULL,

  6. qty int NOT NULL,

  7. PRIMARY KEY(orderid,orderdate));


  1. INSERT INTO rollup SELECT 1,'2010-01-02',3,'A',10;

  2. INSERT INTO rollup SELECT 2,'2010-04-02',2,'B',20;

  3. INSERT INTO rollup SELECT 3,'2010-05-02',1,'A',30;

  4. INSERT INTO rollup SELECT 4,'2010-07-02',3,'D',40;

  5. INSERT INTO rollup SELECT 5,'2011-01-02',4,'A',20;

  6. INSERT INTO rollup SELECT 6,'2011-01-02',3,'B',30;

  7. INSERT INTO rollup SELECT 7,'2011-01-02',1,'C',40;

  8. INSERT INTO rollup SELECT 8,'2009-01-02',2,'A',10;

  9. 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再做一次聚合,即訂單數量總和。
對單個維度進行rollup操作只是可以在最後得到聚合的數據,對比group by語句並沒有非常大的優勢。

對多個維度進行rollup才能體現出rollup的優勢:
(對3列進行層次的維度操作)

  1. SELECT empidcustid,

  2.         YEAR(orderdate) year,

  3.         SUM(qty) sum

  4. FROM rollup

  5. GROUP BY empid,custid,YEAR(orderdate)

  6. WITH ROLLUP;


結果爲


其中(null,null,null)表示最後的聚合
(empid,custid,year)表示對這3列進行分組的聚合結果
(empid,custid,null)表示對(empid,custid)兩列進行分組的聚合結果
(empid,null,null)表示僅對(empid)一列進行分組的聚合結果

所以上述語句等同於(但未排序)

  1. SELECT empidcustidYEAR(orderdate) YEARSUM(qty) sum FROM rollup

  2. GROUP BY empidcustidYEAR(orderdate)

  3. UNION

  4. SELECT empidcustidNULLSUM(qty) sum FROM rollup

  5. GROUP BY empidcustid

  6. UNION

  7. SELECT empidNULLNULLSUM(qty) sum FROM rollup

  8. GROUP BY empid

  9. UNION

  10. SELECT NULLNULLNULLSUM(qty) sum FROM rollup


UNION 操作符用於合併兩個或多個 SELECT 語句的結果集。雖然兩者得到相同的結果,但是執行計劃卻不同,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操作:

  1. SELECT empidcustidYEAR(orderdate)SUM(qty)

  2. FROM rollup

  3. GROUP BY empidcustidYEAR(orderdate)

  4. WITH CUBE;

上述SQL語句會報錯:
-- 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;


產生的最終結果爲:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章