GROUP BY的擴展主要包括ROLLUP,CUBE,GROUPING SETS三種形式。
ROLLUP
rollup相對於簡單的分組合計增加了小計和合計,解釋起來會比較抽象,下面我們來看看具體事例。
例1,統計不同部門工資的總和和所有部門工資的總和。
SQL> select deptno,sum(sal) from emp group by rollup(deptno);
DEPTNO SUM(SAL)
---------- ----------
10 8750
20 10875
30 9400
29025
例2,該例中先對deptno進行分組,再對job進行分組
SQL> select deptno,job,sum(sal) from emp group by rollup(deptno,job);
DEPTNO JOB SUM(SAL)
---------- --------- ----------
10 CLERK 1300 --10號部門中JOB為CLERK的工資的總和
10 MANAGER 2450
10 PRESIDENT 5000
10 8750 --10號所有工種工資的總和
20 CLERK 1900
20 ANALYST 6000
20 MANAGER 2975
20 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 9400
29025 --所有部門,所有工種工資的總和
13 rows selected.
如果要用普通的分組函數實現,可用UNION ALL語句:
--實現單個部門,單個工種的工資的總和
select deptno,job,sum(sal) from emp group by deptno,job union all
--實現單個部門工資的總和
select deptno,null,sum(sal) from emp group by deptno union all
--實現所有部門工資的總和
select null,null,sum(sal) from emp order by 1,2
下面我們分別來看看兩者的執行計劃及統計信息,
ROLLUP語句:
Execution Plan
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 | 132 | 3 (34)| 00:00:01 |
| 1 | SORT GROUP BY ROLLUP| | 11 | 132 | 3 (34)| 00:00:01 |
| 2 | TABLE ACCESS FULL | EMP | 14 | 168 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
895 bytes sent via SQL*Net to client
519 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
13 rows processed
UNION ALL語句:
Execution Plan ----------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 15 | 150 | 9 (34)| 00:00:01 | | 1 | SORT ORDER BY | | 15 | 150 | 8 (75)| 00:00:01 | | 2 | UNION-ALL | | | | | | | 3 | HASH GROUP BY | | 11 | 132 | 3 (34)| 00:00:01 | | 4 | TABLE ACCESS FULL| EMP | 14 | 168 | 2 (0)| 00:00:01 | | 5 | HASH GROUP BY | | 3 | 15 | 3 (34)| 00:00:01 | | 6 | TABLE ACCESS FULL| EMP | 14 | 70 | 2 (0)| 00:00:01 | | 7 | SORT AGGREGATE | | 1 | 3 | | | | 8 | TABLE ACCESS FULL| EMP | 14 | 42 | 2 (0)| 00:00:01 | -----------------------------------------------------------------------------
Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 6 consistent gets 0 physical reads 0 redo size 895 bytes sent via SQL*Net to client 519 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 13 rows processed
不難看出,相同的功能實現,ROLLUP相對於UNION ALL效率有了極大的提升。
CUBE
cube相對於rollup,結果輸出更加詳細。
例1,在本例中還不是很明顯。
SQL> select deptno,sum(sal) from emp group by cube(deptno);
DEPTNO SUM(SAL)
---------- ----------
29025
10 8750
20 10875
30 9400
例2,相對於rollup,cube還對工種這一列進行了專門的匯總。
SQL> select deptno,job,sum(sal) from emp group by cube(deptno,job);
DEPTNO JOB SUM(SAL)
---------- --------- ----------
29025
CLERK 4150
ANALYST 6000
MANAGER 8275
SALESMAN 5600
PRESIDENT 5000
10 8750
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
20 10875
20 CLERK 1900
20 ANALYST 6000
20 MANAGER 2975
30 9400
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
18 rows selected.
GROUPING SETS
GROUPING SETS相對於ROLLUP和CUBE,結果是分類統計的,可讀性更好一些。
例1:
SQL> select deptno,job,to_char(hiredate,'yyyy')hireyear,sum(sal) from emp group by grouping sets(deptno,job,to_char(hiredate,'yyyy'));
DEPTNO JOB HIRE SUM(SAL)
---------- --------- ---- ----------
CLERK 4150
SALESMAN 5600
PRESIDENT 5000
MANAGER 8275
ANALYST 6000
30 9400
20 10875
10 8750
1987 4100
1980 800
1982 1300
1981 22825
例2:
SQL> select deptno,job,sum(sal) from emp group by grouping sets(deptno,job);
DEPTNO JOB SUM(SAL)
---------- --------- ----------
CLERK 4150
SALESMAN 5600
PRESIDENT 5000
MANAGER 8275
ANALYST 6000
30 9400
20 10875
10 8750
8 rows selected.
對於該例,如何用UNION ALL實現呢?
select null deptno,job,sum(sal) from emp group by job union all select deptno,null,sum(sal) from emp group by deptno;
兩者的執行計劃及統計信息分別如下:
GROUPING SETS:
Execution Plan
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 | 352 | 10 (20)| 00:00:01 |
| 1 | TEMP TABLE TRANSFORMATION | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D6795_E71F79 | | | | |
| 3 | TABLE ACCESS FULL | EMP | 14 | 168 | 2 (0)| 00:00:01 |
| 4 | LOAD AS SELECT | SYS_TEMP_0FD9D6796_E71F79 | | | | |
| 5 | HASH GROUP BY | | 1 | 19 | 3 (34)| 00:00:01 |
| 6 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6795_E71F79 | 1 | 19 | 2 (0)| 00:00:01 |
| 7 | LOAD AS SELECT | SYS_TEMP_0FD9D6796_E71F79 | | | | |
| 8 | HASH GROUP BY | | 1 | 26 | 3 (34)| 00:00:01 |
| 9 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6795_E71F79 | 1 | 26 | 2 (0)| 00:00:01 |
| 10 | VIEW | | 1 | 32 | 2 (0)| 00:00:01 |
| 11 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6796_E71F79 | 1 | 32 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
4 recursive calls
24 db block gets
17 consistent gets
3 physical reads
1596 redo size
819 bytes sent via SQL*Net to client
519 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
8 rows processed
UNION ALL:
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 65 | 6 (67)| 00:00:01 |
| 1 | UNION-ALL | | | | | |
| 2 | HASH GROUP BY | | 5 | 50 | 3 (34)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP | 14 | 140 | 2 (0)| 00:00:01 |
| 4 | HASH GROUP BY | | 3 | 15 | 3 (34)| 00:00:01 |
| 5 | TABLE ACCESS FULL| EMP | 14 | 70 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
819 bytes sent via SQL*Net to client
519 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
8 rows processed
和rollup不同的是,grouping sets的效率竟然比同等功能的union all語句低,這實現有點出乎意料。看來,也不可盲目應用Oracle提供的方案,至少,在本例中是如此。