之前一直不知道exists和in的用法與效率,此次的項目中須要用到,因此本身研究了一下。下面是我舉兩個例子說明二者之間的效率問題。java
前言概述:sql
「exists」和「in」的效率問題,涉及到效率問題也就是sql優化:數據庫
1.若子查詢結果集比較小,優先使用in。緩存
2.若外層查詢比子查詢小,優先使用exists。原理是:若匹配到結果,則退出內部查詢並將條件標誌爲true,傳回所有結果資料oracle
由於若用in,則oracle會優先查詢子查詢,而後匹配外層查詢,原理是:in無論匹配到匹配不到都所有匹配完畢,匹配相等就返回true,就會輸出一條元素.性能
若使用exists,則oracle會優先查詢外層表,而後再與內層表匹配優化
也就是:」匹配原則,拿最小記錄匹配大記錄。也就是遍歷的次數越少越好"spa
例子以下:code
1) select * from T_USER1 where exists(select 1 from T_USER2 where T_USER1.jxb_id =T_USER2.jxb_id ) ;xml
T_USER1 數據量小而T_USER2 數據量很是大時,T_USER1 <<T_USER2 時,1) 的查詢效率高。
原理解析:以上查詢使用了exists語句,sql語句如:select a.* from A a where exists(select 1 from B b where a.id=b.id)
exists()會執行A.length次,它並不緩存exists()結果集,由於exists()結果集的內容並不重要,重要的是結果集中是否有記錄,若是有則返回true,沒有則返回false.
它的查詢過程相似於如下過程:
1 List resultSet=[]; 2 Array A=(select * from A) 3 4 for(int i=0;i<A.length;i++) { //這個循環次數越少越好 5 if(exists(A[i].id) { //執行select 1 from B b where b.id=a.id是否有記錄返回 6 resultSet.add(A[i]); 7 } 8 } 9 return resultSet;
當B表比A表數據大時適合使用exists(),由於它沒有那麼遍歷操做,只須要再執行一次查詢就行.
如:A表有10000條記錄,B表有1000000條記錄,那麼exists()會執行10000次去判斷A表中的id是否與B表中的id相等.
如:A表有10000條記錄,B表有100000000條記錄,那麼exists()仍是執行10000次,由於它只執行A.length次,可見B表數據越多,越適合exists()發揮效果
再如:A表有10000條記錄,B表有100條記錄,那麼exists()仍是執行10000次,還不如使用in()遍歷10000*100次,由於in()是在內存裏遍歷比較,而exists()須要查詢數據庫,咱們都知道查詢數據庫所消耗的性能更高,而內存比較很快.
2) select * from T_USER1 where T_USER1.jxb_id in (select T_USER2 .jxb_id from T_USER2 ) ;
T_USER1 數據量很是大而T_USER2數據量小時,T_USER1 >>T_USER2時,2) 的查詢效率高。
原理解析:這裏有條SQL語句:select * from A where id in(select id from B)
以上查詢使用了in語句,in()只執行一次,它查出B表中的全部id字段並緩存起來.以後,檢查A表的id是否與B表中的id相等,若是相等則將A表的記錄加入結果集中,直到遍歷完A表的全部記錄;
它的查詢過程相似於如下過程
List resultSet=[]; Array A=(select * from A); Array B=(select id from B); for(int i=0;i<A.length;i++) { for(int j=0;j<B.length;j++) { if(A[i].id==B[j].id) { resultSet.add(A[i]); break; } } } return resultSet;
能夠看出,當B表數據較大時不適合使用in(),由於它會B表數據所有遍歷一次.
如:A表有10000條記錄,B表有1000000條記錄,那麼最多有可能遍歷10000*1000000次,效率不好.
再如:A表有10000條記錄,B表有100條記錄,那麼最多有可能遍歷10000*100次,遍歷次數大大減小,效率大大提高.
=======================================================================================================
詳解上面的用法:
exists 用法:
其中 「select 1 from T_USER2 where T_USER1.jxb_id =T_USER2.jxb_id」 至關於一個關聯表查詢,至關於
「select 1 from T_USER1,T_USER2 where T_USER1.jxb_id=T_USER2.jxb_id」
這種狀況下不能單獨執行select 1那部分的sql,否則會報語法錯誤的,這也是使用exists須要注意的地方。
「exists(xxx)」就表示括號裏的語句能不能查出記錄,它要查的記錄是否存在。
所以「select 1」這裏的 「1」實際上是可有可無的,換成「*」也沒問題,它只在意括號裏的數據能不能查找出來,是否存在這樣的記錄,若是存在,這 1) 句的where 條件成立。
==============================
in 的用法:
「2) select * from T_USER1 where T_USER1.jxb_id in (select T_USER2 .jxb_id from T_USER2 ) ;
這裏的「in」後面括號裏的語句搜索出來的字段的內容必定要相對應,通常來講,T1和T2這兩個表的a字段表達的意義應該是同樣的,不然這樣查沒什麼意義。注意:兩個字段名稱能夠不一樣,可是表明的東西必定是同樣的才能夠。
打個比方:T1,T2表都有一個字段,表示工單號,可是T1表示工單號的字段名叫「ticketid」,T2則爲「id」,可是其表達的意義是同樣的,並且數據格式也是同樣的。這時,用 2)的寫法就能夠這樣:
1 「select * from T1 where T1.ticketid in (select T2.id from T2) 」 2 3 Select name from employee where name not in (select name from student); 4 5 Select name from employee where not exists (select name from student);
第一句SQL語句的執行效率不如第二句。
總結:
經過使用EXISTS,Oracle會首先檢查主查詢,而後運行子查詢直到它找到第一個匹配項,這就節省了時間。
Oracle在執行IN子查詢時,首先執行子查詢,並將得到的結果列表存放在一個加了索引的臨時表中。在執行子查詢以前,系統先將主查詢掛起,待子查詢執行完畢,存放在臨時表中之後再執行主查詢。
這也就是使用EXISTS比使用IN一般查詢速度快的緣由