1. 程式人生 > >優化器跟蹤分析一個很怪異的現象

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

rac 不同 得來 完全 png users from mys bsp

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

sql2執行計劃:
技術分享圖片

兩條完全相同的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
技術分享圖片

上述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是怎麽得來的呢。下面給出計算公式:
技術分享圖片

表結構:
技術分享圖片

索引idx_duura
技術分享圖片

索引idx_duur
技術分享圖片

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,結合業務修改sql

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