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


  exists和in的使用方式:  

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

  1、exists是對外表做loop循環,每次loop循環再對內表(子查詢)進行查詢,那么因為對內表的查詢使用的索引(內表效率高,故可用大表),而外表有多大都需要遍歷,不可避免(盡量用小表),故內表大的使用exists,可加快效率;

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

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

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

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

而之前的版本則會把非相關子查詢轉化為相關子查詢,導致效率低下(尤其是子查詢是小表,外表是大表的情況下,效率變慢許多)。  

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

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

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

  本來是內表小,用的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; 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM