mysql5.6之后 order by limit 排序分页数据重复问题
young / / / 阅读量

问题

最近在项目中遇到一个特别的问题,使用 order by 排序并进行分页查询的时候,数据会出现重复

# 当xx不存在索引,且有xx相同的行是,可能出现分页数据重复问题
select * from table order by xx limit 0,10

资料

MySQL 5.6的版本上,优化器在遇到order by limit语句的时候,做了一个优化,即使用了priority queue。使用 priority queue 的目的,就是在不能使用索引有序性的时候,如果要排序,并且使用了limit n,那么只需要在排序的过程中,保留n条记录即可,这样虽然不能解决所有记录都需要排序的开销,但是只需要 sort buffer 少量的内存就可以完成排序。之所以5.6出现了第二页数据重复的问题,是因为 priority queue 使用了堆排序的排序方法,而堆排序是一个不稳定的排序方法,也就是相同的值可能排序出来的结果和读出来的数据顺序不一致。

造成原因

基于这个我们就基本知道为什么分页会不准了,因为我们排序的字段是update_date,正好又有几个相同的值的行,在实际执行时返回结果对应的行的顺序是不确定的。对应上面的情况,第一页返回的update_date2020-01-01的数据行,可能正好排在前面,而第四页查询时update_date2020-01-01的数据行正好排在后面,所以第四页又出现了。

因为数据库同一字段的值是有多条数据相同的,order by 字段名 再加上 limit 就会出现问题了

解决办法

唯一的字段加在 order by 中

找一个唯一的字段加在 order by

如果想在Limit存在或不存在的情况下,都保证排序结果相同,可以额外加一个排序条件。例如id字段是唯一的,可以考虑在排序字段中额外加个id排序去确保顺序稳定。

所以上面的情况下可以在SQL再添加个排序字段,比如id字段,这样分页的问题就解决了。修改后的SQL可以像下面这样:

#增加一个唯一的字段(唯一键)
select * from table order by update_date,id limit 0,10

降低数据库版本至5.5

5.5 没有这个优化,所以也就不会出现这个问题。

支付宝捐赠
请使用支付宝扫一扫进行捐赠
微信捐赠
请使用微信扫一扫进行赞赏
有 0 篇文章