天天看點

oracle 中not in 與 not exists 執行效率到底誰高誰低?

網上相關資訊很多很多,到底not in 與 not exists誰的效率高,說實話,我也不知道!

select count(1) from ba_ry_jbxx a where not exists (select b.gmsfzh from ba_ry_zgkssh b where a.gmsfzh = b.gmsfzh);

select count(1) from ba_ry_jbxx a where a.gmsfzh not in (select b.gmsfzh from ba_ry_zgkssh b );

以下針對這兩條語句分析:

說到比較,首先得有共同點才會去比較,共同點就是:都可以查詢a表中的gmsfzh字段的值不在b表中的gmsfzh字段裡的記錄數。

前提條件是首先得保證這兩個語句查詢的資料的正确性,才可以進行效率的比較。

(1)當b表中的gmsfzh字段有空值時,用not in查詢結果為0.是以這兩個語句比較效率就沒有任何意義了!就直接用not exists!

(2)當a表中的gmsfzh字段有空值時,查詢結果固然也不一樣,用 not exists 查詢的記錄數會大于用not in的記錄數,因為 not exists把空值也

作為查詢結果了,而not in不把空值作為結果。

(

至于為什麼,我的了解是:因為not exists會關聯a.gmsfzh = b.gmsfzh一下,除了關聯上的資料其他的在a表中剩下的記錄都認為不在b表中,因為空值肯定是關聯不上的,

是以就認為空值不在b表中。

而為什麼用not in時,a表中的空值就不算在查詢結果内呢!因為oracle就這麼規定的)

是以當a表中的gmsfzh字段有空值時,因為查詢結果都不一樣,你覺得哪個查詢結果是正确的,固然就用哪個!

如果排除兩個表的空值的問題,或者說a表中的空值并不影響查詢結果的正确性時,接下來可以考慮not in 和not exists的執行效率問題了:

資料量情況:a表 100條記錄, b表 70000條記錄,執行以下兩語句:

select count(1) from ba_ry_jbxx a where not exists (select b.gmsfzh from ba_ry_zgkssh b where a.gmsfzh = b.gmsfzh);

select count(1) from ba_ry_jbxx a where a.gmsfzh not in (select b.gmsfzh from ba_ry_zgkssh b );

當兩個表都為gmsfzh字段建了索引的情況下

實測結果如下:

用not exists,耗時0.015秒。

用not in,耗時50.641秒。

這差距還真有點大。。。

毫無疑問,用not exists走索引了,而not in 并不走索引。

當删除兩個表的索引之後:

實測結果如下:

用not exists,耗時50秒。

用not in,耗時 50.875秒,此時not exists和not in 幾乎差不多。

資料量不變,反過來測試:

select count(1) from ba_ry_zgkssh b where not exists (select a.gmsfzh from ba_ry_jbxx a where b.gmsfzh = a.gmsfzh);

select count(1) from ba_ry_zgkssh b where b.gmsfzh not in (select a.gmsfzh from ba_ry_jbxx a );

無索引:

用not in,耗時 3.703秒.

用not exists,耗時3.641秒。(此時至少說明,無索引的情況下,b表資料量遠遠大于a表時,not in與not exists效率差不多)

建完索引後:

用not in,耗時 3.937秒.

用not exists,耗時0.813秒。

以上資料測試可見,索引的重要性。

我總覺得,not in既然存在,肯定有他存在的道理。

測試這麼多,至少證明,有索引的情況下,多數時候not exists完虐not in的執行效率。

現在我糾結的問題就是,到底什麼情況下not in效率要高于not exists? 還請高人留言指點一下。