2011-04-06 43 views
3

我有在其填充一個表中的以下SQLNVL或異常NO_DATA_FOUND

SELECT NVL(SUM(COL1), 0), 
     NVL(SUM(COL2), 0) 
    INTO v_mytable.COLUMN1, 
     v_mytable.COLUMN2 
    FROM t1, t2 
WHERE t1.id = t2.id 
    AND t1.date = t2.date 

還爲表中的行的99%的過程中,這些列= 0和這個查詢需要很長的時間將要執行在大多數情況下,它將在兩列都返回0。

是更好地使用異常HANDELING如下所示:

BEGIN 
    SELECT SUM(COL1), 
     SUM(COL2) 
    INTO v_mytable.COLUMN1, 
     v_mytable.COLUMN2 
    FROM t1, t2 
    WHERE t1.id = t2.id 
    AND t1.date = t2.date 
EXCEPTION WHEN NO_DATA_FOUND THEN 
    v_mytable.COLUMN1 := 0 ; 
    v_mytable.COLUMN2 := 0 ; 
END; 

感謝。

+0

理論上,COALESCE應該比NVL更快,因爲前者由SQL引擎執行,後者由pl/sql執行。但是我懷疑你是否可以衡量差異,特別是因爲它只在查詢結束時調用,而不是每行都調用一次。另外,請參閱Justin Cave的答案,因爲您的代碼永遠不會引發找不到數據。 – redcayuga 2011-04-06 19:16:13

回答

7

這兩個塊做了完全不同的事情。如果COL1和/或COL2始終爲NULL,那麼您的SELECT語句不會拋出NO_DATA_FOUND錯誤。它只會在v_mytable.COLUMN1v_mytable.COLUMN2中放入NULL。

你可以做

SELECT SUM(COL1), 
     SUM(COL2) 
    INTO v_mytable.COLUMN1, 
     v_mytable.COLUMN2 
    FROM t1, t2 
WHERE t1.id = t2.id 
    AND t1.date = t2.date 

v_mytable.COLUMN1 := NVL(v_mytable.COLUMN1, 0); 
v_mytable.COLUMN2 := NVL(v_mytable.COLUMN2, 0); 

我不會期望這是更快了,但是。

3

鑑於這兩者之間的選擇,我會選擇第一個。

我更喜歡使用異常處理程序來處理真正的異常/錯誤,而不是控制流。

YMMV。

+0

同意你的觀點,但在這種情況下,使用異常處理程序甚至不會產生相同的結果。 – 2011-04-06 20:51:41

2

如果沒有行返回,則會拋出NO_DATA_FOUND;如果查詢返回的實際行中返回空值,則返回NOT。這將引發NO_DATA_FOUND:

select sysdate 
into myVariable 
from dual 
where 1=0; 

這不會NO_DATA_FOUND拋出:

select null 
into myVariable 
from dual; 

這就是說,如果你只是想忽略其中COL1和COL2是空行,那麼你可以考慮使用集合中pl/sql,並使用批量收集,如:

select sum(col1) as sum_col1, sum(col2) as sum_col2, col3 
bulk collect into v_mytable 
FROM t1, t2 
WHERE t1.id = t2.id 
    AND t1.date = t2.date 
    AND col1 is not null 
    AND col2 is not null 
GROUP by col3; 

沒有循環,做一舉。僅供參考,您可以設置v_mytable類似:

declare 
    type t_rec is record 
    (col1_sum number, 
    col2_sum number, 
    col3 number); 
    v_rec t_rec; 

    type t_tab is table of v_rec%type; 
    v_mytable t_tab; 

begin 
... 

以後你可以遍歷v_mytable,這將是原來的T1的只有1%,T2(詢問,由於沒有附加條款無效)加入結果。

希望有所幫助。

2

如果您停止加入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。

+0

此外,col1/col2上的索引可以加快速度。 – 2011-04-07 10:19:24

+0

不,它不會:http://download.oracle.com/docs/cd/E11882_01/server.112/e16638/optimops.htm#PFGRF94619 – 2011-04-07 10:56:33

+0

只有當您知道這些值始終是非負數,那麼您可以將謂詞重寫爲col1> 0和col2> 0,在這種情況下,您可以使用索引。 – 2011-04-07 11:12:01