如果您停止加入col值爲0的行,那麼您的SQL將運行得更快。下面是一個小測試來證明我的觀點。
首先創建兩個表10萬行,其中中行的99%有自己的山坳值設置爲0:
SQL> create table t1 (id,date1,col1)
2 as
3 select level
4 , trunc(sysdate)
5 , case mod(level,100) when 42 then 42 else 0 end
6 from dual
7 connect by level <= 100000
8/
Table created.
SQL> create table t2 (id,date2,col2)
2 as
3 select level
4 , trunc(sysdate)
5 , case mod(level,100) when 42 then 84 else 0 end
6 from dual
7 connect by level <= 100000
8/
Table created.
提供基於成本的優化表的統計信息:
SQL> exec dbms_stats.gather_table_stats(user,'t1')
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'t2')
PL/SQL procedure successfully completed.
,採統計運行查詢時:
SQL> set serveroutput off
SQL> alter session set statistics_level = all
2/
Session altered.
現在您的查詢運行如下:
SQL> SELECT NVL(SUM(t1.COL1), 0)
2 , NVL(SUM(t2.COL2), 0)
3 FROM t1
4 , t2
5 WHERE t1.id = t2.id
6 AND t1.date1 = t2.date2
7/
NVL(SUM(T1.COL1),0) NVL(SUM(T2.COL2),0)
------------------- -------------------
42000 84000
1 row selected.
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
2/
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------
SQL_ID 6q5h7h8ht5232, child number 0
-------------------------------------
SELECT NVL(SUM(t1.COL1), 0) , NVL(SUM(t2.COL2), 0) FROM t1 , t2 WHERE t1.id = t2.id AND
t1.date1 = t2.date2
Plan hash value: 446739472
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.37 | 560 | | | |
|* 2 | HASH JOIN | | 1 | 100K| 100K|00:00:00.24 | 560 | 4669K| 1437K| 7612K (0)|
| 3 | TABLE ACCESS FULL| T1 | 1 | 100K| 100K|00:00:00.01 | 280 | | | |
| 4 | TABLE ACCESS FULL| T2 | 1 | 100K| 100K|00:00:00.01 | 280 | | | |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."ID"="T2"."ID" AND "T1"."DATE1"="T2"."DATE2")
21 rows selected.
您可以看到HASH JOIN需要連接100K行,這是大部分時間花費的時間。現在排除0值:
SQL> SELECT NVL(SUM(t1.COL1), 0)
2 , NVL(SUM(t2.COL2), 0)
3 FROM t1
4 , t2
5 WHERE t1.id = t2.id
6 AND t1.date1 = t2.date2
7 and t1.col1 != 0
8 and t2.col2 != 0
9/
NVL(SUM(T1.COL1),0) NVL(SUM(T2.COL2),0)
------------------- -------------------
42000 84000
1 row selected.
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
2/
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------
SQL_ID bjr7wrjx5tjvr, child number 0
-------------------------------------
SELECT NVL(SUM(t1.COL1), 0) , NVL(SUM(t2.COL2), 0) FROM t1 , t2 WHERE t1.id = t2.id AND
t1.date1 = t2.date2 and t1.col1 != 0 and t2.col2 != 0
Plan hash value: 446739472
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.02 | 560 | | | |
|* 2 | HASH JOIN | | 1 | 25000 | 1000 |00:00:00.02 | 560 | 1063K| 1063K| 1466K (0)|
|* 3 | TABLE ACCESS FULL| T1 | 1 | 50000 | 1000 |00:00:00.01 | 280 | | | |
|* 4 | TABLE ACCESS FULL| T2 | 1 | 50000 | 1000 |00:00:00.01 | 280 | | | |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."ID"="T2"."ID" AND "T1"."DATE1"="T2"."DATE2")
3 - filter("T1"."COL1"<>0)
4 - filter("T2"."COL2"<>0)
23 rows selected.
而且你可以看到,散列連接現在只需要加入1000行,從而導致更快的輸出。
希望這會有所幫助。
Regards,
Rob。
理論上,COALESCE應該比NVL更快,因爲前者由SQL引擎執行,後者由pl/sql執行。但是我懷疑你是否可以衡量差異,特別是因爲它只在查詢結束時調用,而不是每行都調用一次。另外,請參閱Justin Cave的答案,因爲您的代碼永遠不會引發找不到數據。 – redcayuga 2011-04-06 19:16:13