专业编程基础技术教程

网站首页 > 基础教程 正文

mysql,order by和limit,你确定会用了吗

ccvgpt 2024-10-16 08:23:26 基础教程 7 ℃

现象描述

select * from table order by xx limit 0,10

看似一句没有问题的sql语句,其实它其中也暗藏着一些坑,既当xx不存在索引,且有xx相同的行是,可能出现分页数据重复问题。想当初在做数据迁移任务时,我以add_time(添加时间,该字段为加索引)为排序字段,总是会报DuplicateKeyException,当时很奇怪,通过日志分析发现分页中某一页的结束行,是另一页的开始行,对这种现象甚是纳闷,想为啥会出现这种现象,经过多方努力查找网络,原理分析如下:

原理分析

这段文字来源mysql官网,该段文字的主要意思就是说,如果order by后面的排序字段存在多个相同值得话,那么mysql排序返回的结果解释不稳定的,mysql会随机返回相同行的记录,从而就有可能出现分页重复问题。

mysql,order by和limit,你确定会用了吗

网上也有对此作了比较详细的解释,就是:

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

不管是官网,还是网上版本的解释,多说明了由于是存在相同行字段作为排序的字段,从而导致mysql返回的结果集不稳定,所以会有可能导致分页重复

解决方案

上面大概意思是说,如果返回相同排序结果在有和没有limit的情况下很重要的话,可以在order by的后面再加上个值唯一的字段,来确保返回结果的稳定性。如下面的操作

让索引字段一同参与排序,假设id为主键,如

select * from table order by xx,id(任意有索引的字段) limit 0,10

附:mysql官网文档地址:https://dev.mysql.com/doc/refman/5.6/en/limit-optimization.html

Tags:

最近发表
标签列表