Mysql orderby limit 索引命中规则

最近做的一个项目,发现了sql慢查询的情况,还好及时发现而且访问量并没有那么大,不然会造成很严重的事故,所以想记录一下,作为自己的成长记录,要不这脑子也不太好使记不住。

表结构不展示啦 直接看索引 (公司的表不方便泄露 假如是table_name吧)
SHOW INDEX FROM table_name (列出索引信息)
在这里插入图片描述
问题sql (我是想通过questionId 进行排序 做分页处理 3475834代表上一页最大的questionId的值 )
EXPLAIN
SELECT QuestionID FROM table_name
WHERE (CourseSectionID in(569743,508457) )
AND (QuestionID > 3475834)
ORDER BY QuestionID
LIMIT 50

在这里插入图片描述
发现rows 的值有 60多万 就是mysql扫表行数有这么多 好恐怖(为什么恐怖自己查去 本节不介绍恐怖原因) 使用的索引是QuestionID和CourseSectionID 的联合索引

优化sql
1.EXPLAIN
SELECT QuestionID FROM table_name
WHERE (CourseSectionID = 569743)
AND (QuestionID > 3475834)
ORDER BY QuestionID
LIMIT 50

在这里插入图片描述
EXPLAIN SELECT QuestionID
FROM table_name
WHERE (CourseSectionID = 508457)
AND (QuestionID > 3475834)
ORDER BY QuestionID
LIMIT 50

在这里插入图片描述
couseSectionId 改成非范围查询的时候 命中的索引是普通索引 courseSectionId 扫表行数分别为621 和1行

2.EXPLAIN
SELECT QuestionID FROM table_name
WHERE (CourseSectionID in(569743,508457) )
AND (QuestionID > 3475834)
ORDER BY QuestionID

在这里插入图片描述
couseSectionId 仍为范围查询 但是去掉了limit 50 索引行数为622

最终解决方案(其实还有别的解决方案 比如说按照表主键id 分页也是可以的 就不细细的说啦)
采用第二种解决方式 把全部的数据查出来在代码层做处理(就是说每次都会查出来600多条 然后在代码层进行limit处理 并且添加了缓存)
sql如下
EXPLAIN
SELECT QuestionID FROM table_name
WHERE (CourseSectionID in(569743,508457) )

所以我们可以总结一下
1. mysql使用orderby limit 时 如果orderby 前面存在范围查询 那么就使用orderby 后面的索引 如果不存在就使用orderby前面的索引
2. 写sql的时候我们可能记不住全部的规则 所以我们一定要使用explain 来确认sql写的是否有问题 然后根据具体的问题去优化sql 有必要就在代码层处理 减轻sql负担
3. 使用orderby limit 时 如果是范围查询并且知道范围是什么 比如说上面的courseSectionId 我们可以采用分开查询的方式可以减少sql的扫表行数

最后还是想说sql性能很重要 explain很重要 写错了可不是开玩笑的嗯嗯 简单介绍这次事故 只能说自己比较幸运 犯的错误在请求量比较小的接口中出现 要是其他的我就惨了