mysql in查詢優化案例


轉載於: https://blog.csdn.net/singgel/article/details/64437777

https://blog.csdn.net/u011383596/article/details/78317243

 

mysql in查詢的執行過程

現在有兩個表,table1和table2,table1有1千萬數據(id 主鍵索引),table2有三條數據(uid字段 3,5,7);

select * from table1 where id in ( select uid from table2 );
眨眼一看感覺這條語句應該很快;可能你會一廂情願的以為 先執行括號里面的語句,然后在執行外層的select;外層的select用上了 id主鍵速度應該飛起來才對;

實際上這條語句執行非常慢,我這里測試20s;

通過  explain 分析,這條語句沒有用上索引,而是全表掃描;原因在哪里?

實際上 mysql 內部不是照着我們的想法來運行的,他是從外層執行起走,每掃一行就把id拿來和內層查詢比較,所以外層是全表掃描;

把這條語句改成:

select * from table1 where id in ( 3,5,7 ); 【補充一點,在mysql內部 in 會被自動轉化為 exists】
執行時間編程毫秒級了,通過explain 查看 使用了range 掃描,可以看出mysql內部操作原理;

然后我們再來看一下有沒有解決方案:

select table1.* from table1 inner join table2 on table1.id=table2.uid;
查詢時間也是毫秒級的;

這次通過 explain 發現  ,mysql先執行了 select uid from table2,然后執行select table1 並且使用了 eq_ref 一對一索引;
————————————————
版權聲明:本文為CSDN博主「阿拉斯加大閘蟹」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/singgel/java/article/details/64437777

 

 

 

 

 

 

 

=======================================================

mysql exists 和 in 運行原理解析

 

這條語句適用於a表比b表大的情況

select * from ecs_goods a where cat_id in(select cat_id from ecs_category);

 

這條語句適用於b表比a表大的情況
select * from ecs_goods a where EXISTS(select cat_id from ecs_category b where a.cat_id = b.cat_id);

 

原因:(轉發)

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次,遍歷次數大大減少,效率大大提升.

結論:in()適合B表比A表數據小的情況

select a.* from A a 
where exists(select 1 from B b where a.id=b.id)

以上查詢使用了exists語句,exists()會執行A.length次,它並不緩存exists()結果集,因為exists()結果集的內容並不重要,重要的是結果集中是否有記錄,如果有則返回true,沒有則返回false.
它的查詢過程類似於以下過程

List resultSet=[];
Array A=(select * from A)

for(int i=0;i<A.length;i++) {
   if(exists(A[i].id) {    //執行select 1 from B b where b.id=a.id是否有記錄返回
       resultSet.add(A[i]);
   }
}
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()需要查詢數據庫,我們都知道查詢數據庫所消耗的性能更高,而內存比較很快.

結論:exists()適合B表比A表數據大的情況

當A表數據與B表數據一樣大時,in與exists效率差不多,可任選一個使用.

 


免責聲明!

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



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