MySQL中exists和in的區別及使用場景

exists和in的使用方式:  mysql

1
#對B查詢涉及id,使用索引,故B表效率高,可用大表 -->外小內大
1
select * from A where exists ( select * from B where A.id=B.id);
1
#對A查詢涉及id,使用索引,故A表效率高,可用大表 -->外大內小
1
select * from A where A.id in ( select id from B);

  一、exists是對外表作loop循環,每次loop循環再對內表(子查詢)進行查詢,那麼由於對內表的查詢使用的索引(內表效率高,故可用大表),而外表有多大都須要遍歷,不可避免(儘可能用小表),故內表大的使用exists,可加快效率;sql

  二、in是把外表和內表作hash鏈接,先查詢內表,再把內表結果與外表匹配,對外表使用索引(外表效率高,可用大表),而內表多大都須要查詢,不可避免,故外表大的使用in,可加快效率。oop

  三、若是用not in ,則是內外表都全表掃描,無索引,效率低,可考慮使用not exists,也可以使用A left join B on A.id=B.id where B.id is null 進行優化。優化

  此外,新近遇到的坑,mysql版本問題:spa

  MySQL版本問題:5.6.5優化了子查詢,引入物化子查詢(針對where clause的subquery),子查詢物化將子查詢結果存入臨時表,確保子查詢只執行一次,該表不記錄重複數據且採用哈希索引查找;code

而以前的版本則會把非相關子查詢轉化爲相關子查詢,致使效率低下(尤爲是子查詢是小表,外表是大表的狀況下,效率變慢許多)。  blog

  相關子查詢:子查詢依賴外層鏈接的返回值;索引

  非相關子查詢:子查詢不依賴外層鏈接的返回值;ci

  子查詢分兩種,from語句(派生表)和where語句(子查詢),派生表的效率要高一些,5.6的優化就是把where語句變成from語句。hash

  原本是內表小,用的in,可是聽說5.6以前的版本會把非相關子查詢改成相關子查詢,就是把in的語句改爲了exists的,結果效率超低。

  實驗說明:派生表join比派生表的速度還要快。而使用in查詢須要不少分鐘尚未查出來。

  

複製代碼
#使用派生表 4.68秒
SELECT id FROM la WHERE cardid IN ( SELECT cardid FROM ( select cardid from la group by cardid having count(1)>50) a) ; #使用派生表的內鏈接 1.26秒 SELECT id FROM la JOIN ( select cardid from la group by cardid having count(1)>50) a ON la.cardid=a.cardid; 
複製代碼
相關文章
相關標籤/搜索