2015-12-18 61 views
2

我有Oracle查詢如下這是正常工作:最有效的方法,以檢查是否存在特定的行數從表

INSERT /*+APPEND*/ INTO historical 
SELECT a.* FROM TEMP_DATA a WHERE NOT EXISTS(SELECT 1 FROM historical WHERE KEY=a.KEY) 

與查詢,當我運行解釋計劃,我注意到,優化程序選擇一個HASH JOIN計劃和成本是相當低的

但是有地指出,在歷史表中存在可以檢查對TEMP_DATA表中有多少行一個新的請求,因此該查詢更改爲:

INSERT /*+APPEND*/ INTO historical 
SELECT a.* FROM TEMP_DATA a WHERE (SELECT COUNT(1) FROM historical WHERE KEY=a.KEY) < 2 

這意味着如果給定鍵(不是主鍵)的歷史數據中存在1行記錄,仍然可以插入數據。

但是用這種方法,查詢速度變慢了很多,成本是原始成本的10倍以上。我也注意到,優化器現在選擇一個NESTED LOOP計劃。

請注意,歷史表是包含索引的分區表。

有反正我可以優化這個嗎?

謝謝。

+0

你有'歷史(關鍵)'的索引嗎? –

+0

如果歷史表是分區的並且有索引,則解釋計劃應該顯示分區和索引掃描的使用。 –

+0

是的,歷史表上的索引很少,包括關鍵字。分區是使用日期列完成的。 – ipohfly

回答

1

以下查詢應該做同樣的事情,應該是更好的性能:

select a.* 
    from temp_data a 
    left 
    join(select key, count(*) cnt 
     from historical 
     group 
      by key 
    ) b 
    on a.key = b.key 
where nvl(b.cnt, 0) < 2; 

希望它可以幫助

+0

謝謝。這個結構爲我提供了重構查詢的基礎,現在它更高效! – ipohfly

0

到@ DirkNM的回答另一種方法是:

select a.* 
from temp_data a 
where not exists (select null 
        from historical h 
        where h.key = a.key 
        and rownum <= 2 
        group by h.key 
        having count(*) > 1); 

你會必須測試您的數據集以確定哪種解決方案適合您。

注意:我不希望新查詢(無論選擇哪個)作爲原始查詢的一致性。

+0

在相關的子查詢中,不需要計算找到的第二行之後的任何行。將'和rownum <= 2'添加到查詢的where子句將告訴Oracle在找到第二行時停止查找更多行。 –

+0

@ShannonSeverance好點!我已經更新了我的答案,以包含您的建議。謝謝 *{:-) – Boneist

相關問題