mysql 優化器本就是為了優化sql語句的查找路徑而存在,當優化器足夠智能的時候,這是一件美事。但是,如果優化器犯二的時候呢?有的時候執行計劃看上去非常好,但是慢的無可救藥。有的時候執行計劃看上去很差,卻跑的很歡。 接下來我們一起來看一下下面的例子:
表結構
total rows
index
sql 1
sql 2
總結
為什麼explain中的rows不一樣,最終的掃描的handler_read_prev一樣呢?
針對以上案例,為什麼mysql 會選擇brokerid 作為索引呢?為什麼不用其他的索引呢?我們來強制指定看看
看樣子,還是不行? 強制索引無效。。。怎麼辦?那我們就應該去看看mysql到底是如何一步一步選擇執行計劃的,還好mysql 5.6 提供了另外一種追蹤途徑 optimizer_trace
大家可以很清晰的看到,mysql在之前還是有很多可以選擇的索引,但是最後
reconsidering_access_paths_for_index_ordering 中卻選擇了brokerid,通路路徑為index_scan.
bug.php?id=70245),裡面說eq_range_index_dive_limit 會影響range查詢計劃,官方文檔确實也是這
麼說的。but,無論我怎麼設定eq_range_index_dive_limit的值,絲毫不會影響執行計劃
那怎麼辦呢?
首先
既然brokerid幹擾其優化器的選擇,如果我将其drop掉,優化器是否能夠選擇正确的索引呢?
果然,mysql選擇了正确的索引,跑起來還不錯。但是那個索引要經常被用到,不能被删除,結果這條道路是走不通的。
其次
再回頭看看trace的選擇,裡面有關于"clause": "group by"? 我就再想,是不是由于group by的原因呢?不清楚,那就試試呗,于是将distinct去掉,試試看
情況貌似好轉了,但是這樣子是不滿足業務邏輯的呀。。。。
于是,再仔細看看sql語句的,發現order by 和 group by 重合了,,,為啥不利用group by來排序呢?
so,sql語句這樣修改一下
從性能上看
distinct,orderby ,group by,limit 這幾個條件放在一起,會給mysql 優化器帶來很大的負擔,建議盡量不要這樣使用。