项目场景閭博主介绍:小黄鸭技术
擅长领域:Java、实用工具、运维
系列专栏:Bug之路
如果文章写作时有错误的地方,请各位大佬指正,一起进步!!!
李欢迎大家点赞➕收藏⭐➕评论支持博主爛
项目中有一个接口返回全量数据,数据量比较大导致页面渲染缓慢,所以改成分页来提高响应速度,按照一个状态status来排序。
问题描述
本来以为利用PageHelper加一下分页,语句中加上 order by status 就ok了,结果实际使用时发现分页中有重复数据。
本来以为利用PageHelper加一下分页,语句中加上 order by status 就ok了,结果实际使用时发现分页中有重复数据。
Java代码示例:
// 设置分页 PageHelper.startPage(param.getCurrentPage(), param.getPageSize()); Listlist = userMapper.selectByPage(user.getClassId());
Mapper示例:
SELECT * FROM user_info WHERe STATUS = 0 AND class_id = '1' ORDER BY STATUS LIMIT 10
原因分析
因为status字段有重复,只是0和1。
原理分析使用priority queue目的在MySQL 5.6的版本上,优化器在遇到order by limit语句的时候,做了一个优化,即使用了priority queue。
就是在不能使用索引有序性的时候,若要排序,并且使用了limit n,那么只需要在排序的过程中,保留n条记录即可。这样虽然不能解决所有记录都需要排序的开销,但是只需要sort buffer 少量的内存就可以完成排序。
- 因为 priority queue 使用了堆排序的排序方法,而堆排序是一个不稳定的排序方法,也就是相同的值可能排序出来的结果和读出来的数据顺序不一致。
- MySQL 5.5版本没有优化,所以不会产生此问题
解决方案
索引字段排序
对排序字段加上索引,利用索引的有序性来解决此问题
再添加一个不会重复的字段来做联合排序
当出现重复时,按照第二个字段排序。
SELECt
*
FROM
user_info
WHERe
STATUS = 0
AND class_id = '1'
ORDER BY
STATUS,id
LIMIT 10
对排序字段加上索引,利用索引的有序性来解决此问题
当出现重复时,按照第二个字段排序。



