在Mysql中我们常常用order by来进行排序,使用limit来进行分页,当需要先排序后分页时我们往往使用类似的写法select * from 表名 order by 排序字段 limt M,N。但是这种写法却隐藏着较深的使用陷阱。在排序字段有数据重复的情况下,会很容易出现排序结果与预期不一致的问题。

比如现在有一张user表,表结构及数据如下:

现在想根据创建时间升序查询user表,并且分页查询,每页2条,那很容易写出sql为:select * from user order by create_time limit pageNo,2;

在执行查询过程中会发现:
1、查询第一页数据时:

2、查询第四页数据时:

user表共有8条数据,有4页数据,但是实际查询过程中第一页与第四页竟然出现了相同的数据。

这是什么情况?难道上面的分页SQL不是先将两个表关联查询出来,然后再排好序,再取对应分页的数据吗???

上面的实际执行结果已经证明现实与想像往往是有差距的,实际SQL执行时并不是按照上述方式执行的。这里其实是Mysql会对Limit做优化,具体优化方式见官方文档:https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
这个是5.7版本的说明,提取几个问题直接相关的点做下说明。

上面官方文档里面有提到如果你将Limit row_count与order by混用,mysql会找到排序的row_count行后立马返回,而不是排序整个查询结果再返回。如果是通过索引排序,会非常快;如果是文件排序,所有匹配查询的行(不带Limit的)都会被选中,被选中的大多数或者全部会被排序,直到limit要求的row_count被找到了。如果limit要求的row_count行一旦被找到,Mysql就不会排序结果集中剩余的行了。

这里我们查看下对应SQL的执行计划:

可以确认是用的文件排序,表确实也没有加额外的索引。所以我们可以确定这个SQL执行时是会找到limit要求的行后立马返回查询结果的。

不过就算它立马返回,为什么分页会不准呢?

官方文档里面做了如下说明:

如果order by的字段有多个行都有相同的值,mysql是会随机的顺序返回查询结果的,具体依赖对应的执行计划。也就是说如果排序的列是无序的,那么排序的结果行的顺序也是不确定的。

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

那这种情况应该怎么解决呢?

官方给出了解决方案:

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

所以上面的情况下可以在SQL再添加个排序字段,比如fund_flow的id字段,这样分页的问题就解决了。修改后的SQL可以像下面这样:
SELECT * FROM user ORDER BY create_time,id LIMIT 6,2;

再次测试问题解决!!

扩展介绍:
Mysql Order by排序原理

Mysql order by与limit混用陷阱的更多相关文章

  1. MySQL在大数据Limit使用

    它已被用于Oracle一世.但今天,很惊讶,MySQL在对数量级的性能,甚至差距如此之大不同的顺序相同的功能. 看看表ibmng(id,title,info)  只要  id key 指数title ...

  2. MySQL 中随机抽样:order by rand limit 的替代方案

    最近由于需要大概研究了一下MYSQL的随机抽取实现方法.举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RA ...

  3. MySQL ORDER BY主键id加LIMIT限制走错索引

    背景及现象 report_product_sales_data表数据量2800万: 经测试,在当前数据量情况下,order by主键id,limit最大到49的时候可以用到索引report_produ ...

  4. mysql同时使用order by和limit查询时的一个严重隐患 -- 丢失数据

    转自: https://blog.csdn.net/tsxw24/article/details/44994835 我经常使用order by和limit来做数据分页显示并排序,一直也没发现过什么问题 ...

  5. MySQL中 order by 与 limit 的执行顺序以及使用实例

    在 MySQL 执行查询的时候,我们可能既要对结果集进行排序又要限制行数,那么此时 order by 与 limit 的执行顺序是怎么样的呢? order by与limit的执行顺序是:先执行orde ...

  6. 采坑笔记——mysql的order by和limit排序问题

    背景说明 今天写出一个十分弱智的bug,记录一下,提醒自己以后别这种犯错,不怕丢人哈~ 在写一个分页查询记录的sql时,要根据添加的时间逆序分页输出,之前的写法是酱紫 select record.a, ...

  7. MySQL中 ORDER BY 与 LIMIT 的执行顺序

    如下: ORDER BY 与 LIMIT 的执行顺序:ORDER BY > LIMIT ORDER BY 与 LIMIT 的编写顺序:ORDER BY > LIMIT 正确写法: sele ...

  8. 为什么MYSQL分页时使用limit+ order by会出现数据重复问题

    问题描述: MYSQL采用limit进行翻页查询时,搭配order by ,在翻到第二页的时候可能会出现第一页的数据,  示例sql如下: select  a,b from c where d = ' ...

  9. MYSQL随机抽取查询 MySQL Order By Rand()效率问题

    MYSQL随机抽取查询:MySQL Order By Rand()效率问题一直是开发人员的常见问题,俺们不是DBA,没有那么牛B,所只能慢慢研究咯,最近由于项目问题,需要大概研究了一下MYSQL的随机 ...

随机推荐

  1. IO流(4)—字符流

    1.IO体系: 抽象基类 --节点流(文件流) InputStream -- FileInputStream OutputStream --FileOutputSteam Reader --FileR ...

  2. MUI学习02-顶部导航栏

    建议:先看一下MUI注意事项 连接:http://ask.dcloud.net.cn/article/122 固定栏靠前 所谓的固定栏,也就是带有.mui-bar属性的节点,都是基于fixed定位的元 ...

  3. 卷积神经网络(CNN)代码实现(MNIST)解析

    在http://blog.csdn.net/fengbingchun/article/details/50814710中给出了CNN的简单实现,这里对每一步的实现作个说明: 共7层:依次为输入层.C1 ...

  4. 阿里云物联网平台体验(树莓派+Python篇)

    阿里云物联网平台体验(树莓派+Python篇) 虽然对阿里云物联网平台比较熟悉了,从一开始就有幸参与了飞凤平台(Link Develop 一站式开发平台的前身)的一些偏硬件接入的工作.但是同时也见证了 ...

  5. iframe之间操作记录

    1.watch.js (function ($) { $.fn.watch = function (callback) { return this.each(function () { //缓存以前的 ...

  6. Unix环境高级编程-阻塞访问原理——等待队列

    有些时候,一个系统调用可能无法马上取到或者送出数据:一个温度采集器如果没有采用中断或者轮询的策略,而是在用户发出请求时才进行采集,并在一定的时间后返回结果.如果用户程序希望调用read或write并且 ...

  7. 安装Docker,Asp.net core

    升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署 Docker从入门到实践 一.安装Docker a).设置Docker仓库 1.按惯例,首先更新Ubuntu的包索引 ...

  8. OC 与 js 界面JSBridge交互

    // 1.新建WebView self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; [self.view addSubv ...

  9. MySQL安装、配置、测试

    MySQL安装.配置.测试(win7_64bit) 目录 1.概述 2.本文用到的工具 3.MySQL安装配置 4.Java访问MySQL测试 5.注事事项 6.相关博文 >>看不清的图片 ...

  10. Hibernate获取数据java.lang.StackOverflowError

    原因:因为在重写toString()方法时,把关联的属性也放入到toString方法中了,去掉就可以了. 如:重写的toString方法中不能有关联关系IDCard属性idCard public cl ...