天天看點

Mysql orderby limit 索引命中規則

最近做的一個項目,發現了sql慢查詢的情況,還好及時發現而且通路量并沒有那麼大,不然會造成很嚴重的事故,是以想記錄一下,作為自己的成長記錄,要不這腦子也不太好使記不住。

Mysql版本 5.6.25

表結構不展示啦 直接看索引 (公司的表不友善洩露 假如是table_name吧)

SHOW INDEX FROM table_name (列出索引資訊)

Mysql orderby limit 索引命中規則

問題sql (我是想通過questionId 進行排序 做分頁處理 3475834代表上一頁最大的questionId的值 )

EXPLAIN

SELECT QuestionID FROM table_name

WHERE (CourseSectionID in(569743,508457) )

AND (QuestionID > 3475834)

ORDER BY QuestionID

LIMIT 50

Mysql orderby limit 索引命中規則

發現rows 的值有 60多萬 就是mysql掃表行數有這麼多 好恐怖(為什麼恐怖自己查去 本節不介紹恐怖原因) 使用的索引是QuestionID和CourseSectionID 的聯合索引

優化sql

1.EXPLAIN

SELECT QuestionID FROM table_name

WHERE (CourseSectionID = 569743)

AND (QuestionID > 3475834)

ORDER BY QuestionID

LIMIT 50

Mysql orderby limit 索引命中規則

EXPLAIN

SELECT QuestionID

FROM table_name

WHERE (CourseSectionID = 508457)

AND (QuestionID > 3475834)

ORDER BY QuestionID

LIMIT 50

Mysql orderby limit 索引命中規則

couseSectionId 改成非範圍查詢的時候 命中的索引是普通索引 courseSectionId 掃表行數分别為621 和1行

2.EXPLAIN

SELECT QuestionID FROM table_name

WHERE (CourseSectionID in(569743,508457) )

AND (QuestionID > 3475834)

ORDER BY QuestionID

Mysql orderby limit 索引命中規則

couseSectionId 仍為範圍查詢 但是去掉了limit 50 索引行數為622

最終解決方案(其實還有别的解決方案 比如說按照表主鍵id 分頁也是可以的 就不細細的說啦)

采用第二種解決方式 把全部的資料查出來在代碼層做處理(就是說每次都會查出來600多條 然後在代碼層進行limit處理 并且添加了緩存)

sql如下

EXPLAIN

SELECT QuestionID FROM table_name

WHERE (CourseSectionID in(569743,508457) )

是以我們可以總結一下(在5.6.25版本下 其他版本還沒有嘗試 不同版本的文法解析不同可能索引的使用規則也不同)

1. mysql使用orderby limit 時 如果orderby 前面存在範圍查詢 那麼就使用orderby 後面的索引 如果不存在就使用orderby前面的索引

2. 寫sql的時候我們可能記不住全部的規則 是以我們一定要使用explain 來确認sql寫的是否有問題 然後根據具體的問題去優化sql 有必要就在代碼層處理 減輕sql負擔

3. 使用orderby limit 時 如果是範圍查詢并且知道範圍是什麼 比如說上面的courseSectionId 我們可以采用分開查詢的方式可以減少sql的掃表行數

最後還是想說sql性能很重要 explain很重要 寫錯了可不是開玩笑的嗯嗯 簡單介紹這次事故 隻能說自己比較幸運 犯的錯誤在請求量比較小的接口中出現 要是其他的我就慘了