使用索引優化left join on + where條件查詢


首先,貼一個待優化的sql語句

select * from A left join B on A.c = B.c where A.employee_id = 3

需求解讀:

  • A表left join B表,並且指定A表中的employee_id為一個具體的值
在c字段不是任何索引,A B 表各有1W多條數據的情況下,用explain分析得知,AB表都使用了全表查詢,效率極低

而我們執行這句sql的時間,即使使用的是本地SSD硬盤也達到了驚人的16S

優化 :

  • 給AB表都加索引列c
    這一點網上都有大片介紹,但網上的說明也就到此為止而已

讓我們看看結果

 可以看到,確實是使用了索引!我們看看執行分析

16s多的查詢,僅用了0.1s!很多人的優化之路到這里就結束了,但真的大功告成了嗎?

 思考:表A和表B中都加了索引,然而查詢過程卻是表A進行了全表掃描,如果非要全表掃描一個的話,為什么全表掃描的不是表B?

因為Mysql內部的優化,使用小表驅動大表,
它在估算到必須有一個表要全表掃描的話,一定會選擇那個數據量更小的表去全表掃描,
也就是說,在這個查詢中,因為on以后的where條件列並沒有使用到索引,
所以mysql的優化只用到了表B的c索引,沒有用到表A的索引!

分析得知,查詢看似快了不少,然而表A還是進行了全表查詢,而我們的查詢中使用了where語句,根本就不需要全表掃描!!

那么問題來了:where條件中employee_id 的索引應該怎么加?

嘗試解決:

  • 將A表中的索引改為employee_id+c

 sql分析:

看似沒有問題?確實是用到了employee_id+c的索引,但是

思考:sql執行 from中的on應該是優先於where語句的,為什么這里employee_id反而在c之前?有違常理?

結合上面的Mysql優化可知,
這一句Sql在執行的時候首先是選擇了使用表B的索引來進行優化,
將表A單獨放出來進行后續的操作,
然后,又發現了where語句中A.employee_id有一個聚合索引,
並且employee_id處於索引頭,所以這個聚合索引是可用的,
so自然使用了此索引

為了證明這個觀點,我們把聚合索引后面的列c刪掉試試:

 sql分析:

查詢結果和剛才的聚合索引沒有任何變化,證明我們的猜測是正確的

看看最終的查詢時間:

掃描的A表中記錄數從10557條縮小到了符合A.employee_id=3的69條,100多倍的差距!

如果數據量不是1萬 而是100萬,100億,沿用之前的sql,系統還能穩定運行嗎?

 


免責聲明!

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



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