DATE型別擷取到天的效率
在ITPUB上看了一個帖子,根據日期型別對每天的記錄進行GROUP BY,帖子的地址如下:http://www.itpub.net/thread-1564295-1-1.html
這種包含全表掃描執行GROUP BY的語句是否還有最佳化的餘地嗎,事實上確實還有,因為對於處理日期型別,TO_CHAR並沒有TRUNC高效。
下面看一個簡單的例子:
SQL> CREATE TABLE T_DATE AS
2
SELECT ROWNUM ID, CREATED
3
FROM DBA_OBJECTS A, (SELECT 1 FROM DUAL CONNECT BY ROWNUM < 100)
4
WHERE ROWNUM <= 1000000;
Table created.
SQL> SELECT COUNT(*) FROM T_DATE;
COUNT(*)
----------
1000000
SQL> SET TIMING ON
SQL> SELECT TO_CHAR(CREATED, 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TO_CHAR(CREATED, 'YYYY-MM-DD');
TO_CHAR(CR COUNT(*)
---------- ----------
2012-01-07 3600
2012-01-08 3750
2012-01-09 4650
2012-01-06 987925
2012-01-10 75
Elapsed: 00:00:00.46
SQL> SELECT TO_CHAR(CREATED, 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TO_CHAR(CREATED, 'YYYY-MM-DD');
TO_CHAR(CR COUNT(*)
---------- ----------
2012-01-07 3600
2012-01-08 3750
2012-01-09 4650
2012-01-06 987925
2012-01-10 75
Elapsed: 00:00:00.40
SQL> SELECT TO_CHAR(CREATED, 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TO_CHAR(CREATED, 'YYYY-MM-DD');
TO_CHAR(CR COUNT(*)
---------- ----------
2012-01-07 3600
2012-01-08 3750
2012-01-09 4650
2012-01-06 987925
2012-01-10 75
Elapsed: 00:00:00.39
SQL> SELECT TO_CHAR(CREATED, 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TO_CHAR(CREATED, 'YYYY-MM-DD');
TO_CHAR(CR COUNT(*)
---------- ----------
2012-01-07 3600
2012-01-08 3750
2012-01-09 4650
2012-01-06 987925
2012-01-10 75
Elapsed: 00:00:00.44
SQL> SELECT TO_CHAR(TRUNC(CREATED), 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TRUNC(CREATED);
TO_CHAR(TR COUNT(*)
---------- ----------
2012-01-06 987925
2012-01-10 75
2012-01-08 3750
2012-01-07 3600
2012-01-09 4650
Elapsed: 00:00:00.36
SQL> SELECT TO_CHAR(TRUNC(CREATED), 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TRUNC(CREATED);
TO_CHAR(TR COUNT(*)
---------- ----------
2012-01-10 75
2012-01-07 3600
2012-01-09 4650
2012-01-06 987925
2012-01-08 3750
Elapsed: 00:00:00.35
SQL> SELECT TO_CHAR(TRUNC(CREATED), 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TRUNC(CREATED);
TO_CHAR(TR COUNT(*)
---------- ----------
2012-01-10 75
2012-01-07 3600
2012-01-09 4650
2012-01-06 987925
2012-01-08 3750
Elapsed: 00:00:00.36
SQL> SELECT TO_CHAR(TRUNC(CREATED), 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TRUNC(CREATED);
TO_CHAR(TR COUNT(*)
---------- ----------
2012-01-10 75
2012-01-07 3600
2012-01-09 4650
2012-01-06 987925
2012-01-08 3750
Elapsed: 00:00:00.34
如果僅從執行計劃和邏輯讀上進行分析,兩個SQL沒有任何區別:
SQL> set autot on
SQL> SELECT TO_CHAR(CREATED, 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TO_CHAR(CREATED, 'YYYY-MM-DD');
TO_CHAR(CR COUNT(*)
---------- ----------
2012-01-07 3600
2012-01-08 3750
2012-01-09 4650
2012-01-06 987925
2012-01-10 75
Elapsed: 00:00:00.43
Execution Plan
----------------------------------------------------------
Plan hash value: 534547868
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows
| Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT |
| 1294K| 11M|
726 (6)| 00:00:09 |
| 1 |
HASH GROUP BY | |
1294K| 11M| 726
(6)| 00:00:09 |
| 2 |
TABLE ACCESS FULL| T_DATE |
1294K| 11M| 694
(1)| 00:00:09 |
-----------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this
statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2490 consistent gets
2487 physical reads
0 redo size
754 bytes sent via SQL*Net to client
524 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
5
rows processed
SQL> SELECT TO_CHAR(TRUNC(CREATED), 'YYYY-MM-DD'), COUNT(*)
2
FROM T_DATE
3
GROUP BY TRUNC(CREATED);
TO_CHAR(TR COUNT(*)
---------- ----------
2012-01-10 75
2012-01-07 3600
2012-01-09 4650
2012-01-06 987925
2012-01-08 3750
Elapsed: 00:00:00.34
Execution Plan
----------------------------------------------------------
Plan hash value: 534547868
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows
| Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT |
| 1294K| 11M|
726 (6)| 00:00:09 |
| 1 |
HASH GROUP BY | |
1294K| 11M| 726
(6)| 00:00:09 |
| 2 |
TABLE ACCESS FULL| T_DATE |
1294K| 11M| 694
(1)| 00:00:09 |
-----------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this
statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2490 consistent gets
2487 physical reads
0 redo size
761 bytes sent via SQL*Net to client
524 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
5 rows processed
但是觀察兩個SQL的平均執行時間,會發現使用TRUNC方式比TO_CHAR有1/8的效能提升,對於執行計劃完全相同的情況而言,這個比率已經很高了。
其實導致問題的原因在於DATE型別的儲存,DATE由7個位元組組成,分別為世紀、年、月、日、時、分、秒。對於TRUNC函式而言,只是簡單的捨棄掉後面三個位元組,因此效率最高,而TO_CHAR需要將內部的儲存格式轉化為字元格式,顯然會消耗更多的資源。
兩個SQL返回結果順序的不同也說明了這一點,TRUNC函式進行HASH GROUP的是日期格式,而TO_CHAR函式進行HASH GROUP的是字元型別,導致了最終結果返回順序的差異性。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-714647/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- date型別型別
- Date型別和Regex型別型別
- long型別資料的擷取型別
- DATE型別INTERVAL分割槽型別
- date型別的內部結構型別
- Date簡單型別的setter注入型別
- 將timestamp型別轉換為date型別型別
- 檔案路徑類 字串的各種擷取方式,包括擷取到檔名字串
- date、timestamp欄位型別型別
- ibatis查詢date型別BAT型別
- Oracle中date型別使用注意Oracle型別
- ORACLE DATE型別和TIMESTAMP型別DUMP換算Oracle型別
- oracle timestamp轉換date及date型別相減Oracle型別
- SQL Server日期資料型別DATE的使用SQLServer資料型別
- 字串和Date型別之間的轉換字串型別
- mongoose的date型別和timestamps的使用Go型別
- 一個簡單函式—Number型別轉換Date型別函式型別
- oracle中date資料型別與timestamp資料型別的轉換Oracle資料型別
- date和timestamp型別之間的轉換型別
- air 讀取sqlite的Date型別 解決方案AISQLite型別
- 【Hive】日期從整形轉為Date型別Hive型別
- MYSQL-資料型別儲存-DATEMySql資料型別
- MySQL TEXT、DATE、SET 資料型別(轉)MySql資料型別
- SQL*Plus中使用DATE型別的繫結變數SQL型別變數
- oracle資料型別date和timestamp的轉化Oracle資料型別
- (轉)PLS_INTEGER型別與timestamp型別、date、及時間函式型別函式
- oracle將表中date資料型別修改為timestamp資料型別Oracle資料型別
- Mysql日期(DATE, TIME, DATETIME, TIMESTAMP)型別的比較MySql型別
- jackson 中JsonFormat date型別欄位的使用JSONORM型別
- 資料庫中Date型別的計算 DATEDIFF() 函式資料庫型別函式
- JS原生Date型別方法的一些冷知識JS型別
- 關於Ibatis 轉換 oracle date型別的問題BATOracle型別
- Oracle date 型別比較和String比較Oracle型別
- java處理資料庫date型別資料Java資料庫型別
- Date型別使用Calendar進行時間運算型別
- Oracle concept 學習 2--DATE型別的RR和YYOracle型別
- ORACLE DATE和TIMESTAMP資料型別的比較(一) (轉)Oracle資料型別
- ORACLE DATE和TIMESTAMP資料型別的比較(二) (轉)Oracle資料型別