兩層GROUP BY效率反而比一層GROUP BY效率高——SQL優化之Everything is possible
在一般的優化思想中,都是要儘可能減少巢狀的層數,減少不必要的操作。但是今天發現有的時候並非實際情況卻並非如此。
看下面的例子:
SQL> CREATE TABLE T AS SELECT * FROM DBA_OBJECTS;
表已建立。
SQL> INSERT INTO T SELECT * FROM T;
已建立32774行。
SQL> INSERT INTO T SELECT * FROM T;
已建立65548行。
SQL> INSERT INTO T SELECT * FROM T;
已建立131096行。
SQL> INSERT INTO T SELECT * FROM T;
已建立262192行。
SQL> COMMIT;
提交完成。
SQL> SET AUTOT TRACE
SQL> SET TIMING ON
SQL> COL PLAN_PLUS_EXP FORMAT A80
SQL> SET LINES 110
SQL> SELECT OBJECT_TYPE, COUNT(DISTINCT CREATED)
2 FROM T
3 GROUP BY OBJECT_TYPE;
已選擇34行。
已用時間: 00: 00: 01.31
執行計劃
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (GROUP BY)
2 1 TABLE ACCESS (FULL) OF 'T'
統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
3549 consistent gets
108 physical reads
0 redo size
1099 bytes sent via SQL*Net to client
386 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
34 rows processed
SQL> SELECT OBJECT_TYPE, COUNT(CREATED)
2 FROM
3 (
4 SELECT OBJECT_TYPE, CREATED
5 FROM T
6 GROUP BY OBJECT_TYPE, CREATED
7 )
8 GROUP BY OBJECT_TYPE;
已選擇34行。
已用時間: 00: 00: 00.79
執行計劃
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (GROUP BY)
2 1 VIEW
3 2 SORT (GROUP BY)
4 3 TABLE ACCESS (FULL) OF 'T'
統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
3549 consistent gets
109 physical reads
0 redo size
1091 bytes sent via SQL*Net to client
386 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
34 rows processed
從統計資訊上看,兩個SQL的統計資訊完全一致。而從執行計劃上看,前者只有一次GROUP BY操作,而後者需要GROUP BY兩次,巢狀的層數也比前者多。
但是從執行時間上看,卻是後者比前者的速度更快。所用時間只有前者的60%。
開始我也很不理解,但是仔細考慮了一下,認為可能的主要原因是COUNT(DISTINCT CREATED)操作比較費時。
對於第二個查詢而言,雖然需要GROUP BY操作兩次,但是由於第二次GROUP BY的欄位OBJECT_TYPE就是第一次GROUP BY欄位中的一部分,資料是按照順序從第一步得到的,這裡的GROUP BY操作中最費時的排序其實基本上沒有去做,整個GROUP BY就是一個計算CREATED個數的操作。
而對於第一個查詢,雖然只有一層,且查詢只對OBJECT_TYPE進行了GROUP BY,但是COUNT(DISTINCT CREATED)操作並不是簡單的計數,而是要統計不同的CREATED值。雖然從統計資訊沒有看到排序操作,但是由於要計算不同的CREATED值,Oracle肯定需要儲存並比較CREATED的值,懷疑這個操作比GROUP BY操作的效率要低,這就是造成了兩個GROUP BY效率比一個GROUP BY效率還高的原因。
這個問題同時也說明一個問題,雖然99%的情況下,通過邏輯讀來判斷SQL執行效率都是準確的,但是這個SQL給出了一個反例。在邏輯讀和物理讀都相同的情況下,SQL的執行效率還是可能有很大的差別了。這個例子中的差別無論從統計資訊還是從執行計劃中都是無法發現的。
下面看一個更加極端的例子:
SQL> SELECT OBJECT_TYPE, COUNT(DISTINCT CREATED) CREATED, COUNT(DISTINCT STATUS) STATUS
2 FROM T
3 GROUP BY OBJECT_TYPE;
已選擇34行。
已用時間: 00: 00: 01.78
執行計劃
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (GROUP BY)
2 1 TABLE ACCESS (FULL) OF 'T'
統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
3549 consistent gets
0 physical reads
0 redo size
1217 bytes sent via SQL*Net to client
386 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
34 rows processed
SQL> SELECT B.OBJECT_TYPE, CREATED, STATUS
2 FROM
3 (
4 SELECT OBJECT_TYPE, COUNT(CREATED) CREATED
5 FROM
6 (
7 SELECT OBJECT_TYPE, CREATED
8 FROM T
9 GROUP BY OBJECT_TYPE, CREATED
10 )
11 GROUP BY OBJECT_TYPE
12 ) B,
13 (
14 SELECT OBJECT_TYPE, COUNT(STATUS) STATUS
15 FROM
16 (
17 SELECT OBJECT_TYPE, STATUS
18 FROM T
19 GROUP BY OBJECT_TYPE, STATUS
20 )
21 GROUP BY OBJECT_TYPE
22 ) C
23 WHERE B.OBJECT_TYPE = C.OBJECT_TYPE;
已選擇34行。
已用時間: 00: 00: 01.14
執行計劃
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
2 1 VIEW
3 2 SORT (GROUP BY)
4 3 VIEW
5 4 SORT (GROUP BY)
6 5 TABLE ACCESS (FULL) OF 'T'
7 1 SORT (JOIN)
8 7 VIEW
9 8 SORT (GROUP BY)
10 9 VIEW
11 10 SORT (GROUP BY)
12 11 TABLE ACCESS (FULL) OF 'T'
統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
7098 consistent gets
0 physical reads
0 redo size
1217 bytes sent via SQL*Net to client
386 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
34 rows processed
這兩個SQL是等價的,但是第二個SQL的統計資訊中邏輯讀是第一個的二倍,排序次數是第一個SQL的5倍。從執行計劃上看,更是比第一個SQL不知道複雜多少倍。但是執行時間卻只有第一個SQL的64%。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-69147/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- UNION效率比UNION ALL效率高——SQL優化之Everything is possibleSQL優化
- 【轉】UNION效率比UNION ALL效率高——SQL優化之Everything is possibleSQL優化
- 增加Distinct後查詢效率反而提高——SQL優化之Everything is possibleSQL優化
- Group by 優化優化
- 增加索引改變執行計劃——SQL優化之Everything is possible索引SQL優化
- oracle之優化一用group by或exists優化distinctOracle優化
- SQL -去重Group by 和Distinct的效率SQL
- SQL之19深入group bySQL
- SQL之18深入group bySQL
- SQL之17深入group bySQL
- 恆等查詢條件改變執行計劃——SQL優化之Everything is PossibleSQL優化
- Oracle PL/SQL之GROUP BY CUBEOracleSQL
- sql用法——group bySQL
- sql優化用group by 函式代替分析函式SQL優化函式
- SQL中Group By的使用SQL
- SQL 分組排序group bySQL排序
- SQL入門之4 group by 與子查詢SQL
- group by排序,derived_merge優化的坑排序優化
- 【Hive】資料傾斜優化 shuffle, join, group byHive優化
- 標量子查詢優化(用group by 代替distinct)優化
- JAVA開發之簡化Dao層、提高開發效率Java
- 效能優化-合成層優化
- PostgreSQL DBA(186) - SQL Group BySQL
- sql case when, Exist ,group by ,聚合SQL
- sql中的left切割 與 group by後的兩次分組SQL
- oracle全文索引之SECTION GROUP_6_PATH_SECTION_GROUPOracle索引
- oracle全文索引之SECTION GROUP_5_AUTO_SECTION_GROUPOracle索引
- oracle全文索引之SECTION GROUP_4_XML_SECTION_GROUPOracle索引XML
- oracle全文索引之SECTION GROUP_3_HTML_SECTION_GROUPOracle索引HTML
- oracle全文索引之SECTION GROUP_2_BASIC_SECTION_GROUPOracle索引
- oracle全文索引之SECTION GROUP_1_NULL_SECTION_GROUPOracle索引Null
- three.js之GroupJS
- sql語句中where一定要放在group by 之前SQL
- JAVA開發之簡化Dao層、提高開發效率(二)Java
- JAVA開發之簡化Dao層、提高開發效率(三)Java
- iOS圖層效能優化iOS優化
- Chrome 渲染優化 - 層模型Chrome優化模型
- MySQL最佳化GROUP BY方案MySql