優化器跟蹤分析一個很怪異的現象

工做中遇到一則很奇怪的真實案例,有一個統計sql,統計結果在190-200之間時,耗時基本上維持在1.6S,統計結果在此數據範圍外的統計耗時,基本上維持在0.1-0.3S之間,
按照慣例,explain查看執行計劃。
爲方便闡述,約定以下 :
數據範圍在190-200,耗時1.6S的叫 sql1,數據範圍不在此範圍,耗時0.1-0.3S的叫sql2
sql1執行計劃:
mysql

sql2執行計劃:
sql

兩條徹底相同的sql就篩選條件中換了一個departid的值,sql1 191條記錄,sql2 256條記錄,把sql2的departid換成一個記錄數比較多或者比較少的時候,執行計劃都不變。
爲何惟獨190-200條記錄以前,mysql會採用不一樣的索引呢?
爲了搞清楚這個問題,借用optimizer trace功能
mysql默認不開啓優化器跟蹤功能,開啓方法以下
set gloal optimizer_tracer='enabled=on,one_line=on'; # 開啓優化器跟蹤,並只記錄最後一條sql的跟蹤。關閉將兩個on修改爲off便可
查詢優化器的信息:
select trace from information_schema.optimizer_trace
執行過程當中發現trace字段記錄不全,可經過調大參數optimizer_trace_max_mem_size來設置
如下是sql1和sql2的部分trace信息
sql1
優化

sql2
3d

上述trace能夠看出,SQL1優化器內部評估cost=249.6是成本最小的執行計劃,走idx_duura索引,access_type採用了ref,sql2優化內部評估302.4是成本最低的走了idx_duur索引,access_type採用了range,原本sql2的應該是ref,可是優化器認爲採用range會使用上index上更多的索引鍵(「users_more_keyparts」),這是mysql自身的優化。
在回到上面的執行計劃,sql1的key_len=46,ref=const,const,const,46是怎麼得來的呢。下面給出計算公式:
orm

表結構:
blog

索引idx_duura
索引

索引idx_duur
io

sql中where條件用到了delete_flag,user_mode,user_type,ruleid
sql1執行計劃中的key_len計算方法:1 * 3 + 2 + 10 * 3 + 1 + 2 + 2 * 3 + 2 = 46,用到了三個值,與ref=const,const,const相符
sql2執行計劃中的key_len計算方法:1 * 3 + 2 + 10 * 3 + 1 + 2 + 2 * 3 + 2  + 40 * 3 + 2 = 168,同時使用了四個字段,過濾性更好。
以上已經知道了這怪異現象的緣由,那應該如何解決呢?
1,根據實際業務場景考慮是否使用force index
2,結合業務修改sqlform

相關文章
相關標籤/搜索