首先,貼一個待優化的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,系統還能穩定運行嗎?