小心避坑:MySQL分页时使用 limit+order by 会出现数据重复问题
点击上方“Java知音”,选择“置顶公众号”
技术文章第一时间送达!
作者:猿码道
www.jianshu.com/p/544c319fd838
0 问题描述
在MySQL中我们通常会采用limit来进行翻页查询,比如limit(0,10)表示列出第一页的10条数据,limit(10,10)表示列出第二页。但是,当limit遇到order by的时候,可能会出现翻到第二页的时候,竟然又出现了第一页的记录。
具体如下:
SELECT`post_title`,`post_date`
FROMpost
WHERE`post_status` = 'publish'
ORDER BYview_count desc
LIMIT5, 5
使用上述SQL查询的时候,很有可能出现和LIMIT 0,5相同的某条记录。而如果使用如下方式,则不会出现重复的情况:
SELECT*
FROMpost
WHEREpost_status = 'publish'
ORDER BYview_count desc
LIMIT5, 5
但是,由于post表的字段很多,仅仅希望用这两个字段,不想把post_content也查出来。为了解决这个情况,在ORDER BY后面使用了两个排序条件来解决这个问题,如下:
SELECT`post_title`,`post_date`
FROMpost
WHERE`post_status` = 'publish'
ORDER BYview_count desc,ID asc
LIMIT5, 5
按理来说,MySQL的排序默认情况下是以主键ID作为排序条件的,也就是说,如果在view_count相等的情况下,主键ID作为默认的排序条件,不需要我们多此一举加ID asc。但是事实就是,MySQL再order by和limit混用的时候,出现了排序的混乱情况。
1 分析问题
在MySQL 5.6的版本上,优化器在遇到order by limit语句的时候,做了一个优化,即 使用了priority queue。
使用 priority queue 的目的,就是在不能使用索引有序性的时候,如果要排序,并且使用了limit n,那么只需要在排序的过程中,保留n条记录即可,这样虽然不能解决所有记录都需要排序的开销,但是只需要 sort buffer 少量的内存就可以完成排序。
之所以MySQL 5.6出现了第二页数据重复的问题,是因为 priority queue 使用了堆排序的排序方法,而堆排序是一个不稳定的排序方法,也就是相同的值可能排序出来的结果和读出来的数据顺序不一致。
MySQL 5.5 没有这个优化,所以也就不会出现这个问题。
也就是说,MySQL 5.5是不存在本文提到的问题的,5.6版本之后才出现了这种情况。
再看下MySQL解释sql语言时的执行顺序:
(1) SELECT
(2) DISTINCT <select_list>
(3) FROM <left_table>
(4) <join_type> JOIN <right_table>
(5) ON <join_condition>
(6) WHERE <where_condition>
(7) GROUP BY <group_by_list>
(8) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>
执行顺序依次为 form… where… select… order by… limit…,由于上述priority queue的原因,在完成select之后,所有记录是以堆排序的方法排列的,在进行order by时,仅把view_count值大的往前移动。
但由于limit的因素,排序过程中只需要保留到5条记录即可,view_count并不具备索引有序性,所以当第二页数据要展示时,mysql见到哪一条就拿哪一条,因此,当排序值相同的时候,第一次排序是随意排的,第二次再执行该sql的时候,其结果应该和第一次结果一样。
2 解决方法
1.索引排序字段
如果在字段添加上索引,就直接按照索引的有序性进行读取并分页,从而可以规避遇到的这个问题。
2.正确理解分页
分页是建立在排序的基础上,进行了数量范围分割。排序是数据库提供的功能,而分页却是衍生出来的应用需求。
在MySQL和Oracle的官方文档中提供了limit n和rownum < n的方法,但却没有明确的定义分页这个概念。
还有重要的一点,虽然上面的解决方法可以缓解用户的这个问题,但按照用户的理解,依然还有问题:比如,这个表插入比较频繁,用户查询的时候,在read-committed的隔离级别下,第一页和第二页仍然会有重合。
所以,分页一直都有这个问题,不同场景对数据分页都没有非常高的准确性要求。
3.一些常见的数据库排序问题
不加order by的时候的排序问题
用户在使用Oracle或MySQL的时候,发现MySQL总是有序的,Oracle却很混乱,这个主要是因为Oracle是堆表,MySQL是索引聚簇表的原因。所以没有order by的时候,数据库并不保证记录返回的顺序性,并且不保证每次返回都一致的。
分页问题 分页重复的问题
如前面所描述的,分页是在数据库提供的排序功能的基础上,衍生出来的应用需求,数据库并不保证分页的重复问题。
NULL值和空串问题
不同的数据库对于NULL值和空串的理解和处理是不一样的,比如Oracle NULL和NULL值是无法比较的,既不是相等也不是不相等,是未知的。而对于空串,在插入的时候,MySQL是一个字符串长度为0的空串,而Oracle则直接进行NULL值处理。
END
Java面试题专栏
【40期】说一下线程池内部工作原理
【39期】Mybatis面试18问,你想知道的都在这里了!
【38期】一份tcp、http面试指南,常考点都给你了
【37期】请你详细说说类加载流程,类加载机制及自定义类加载器
【36期】说说 如何停止一个正在运行的线程?
【35期】谈谈你对Java线程之间通信方式的理解
【34期】谈谈为什么要拆分数据库?有哪些方法?
【33期】分别谈谈联合索引生效和失效的条件
【32期】你知道Redis的字符串是怎么实现的吗?
【31期】了解什么是 redis 的雪崩、穿透和击穿?redis 崩溃之后会怎么样?应对措施是什么
我知道你 “在看”
小心避坑:MySQL分页时使用 limit+order by 会出现数据重复问题相关推荐
- layui分页limit不显示_小心避坑:MySQL分页时使用 limit+order by 会出现数据重复问题...
20大进阶架构专题每日送达 来源:www.jianshu.com/p/544c319fd838 进入主题前先插一下,当当优惠码福利来一波!当当全场自营图书5折,用优惠码:J2JYFK(长按复制),满2 ...
- mysql scrapy 重复数据_小心避坑:MySQL分页时使用 limit+order by 会出现数据重复问题...
作者:猿码道http://www.jianshu.com/p/544c319fd838 0 问题描述 在MySQL中我们通常会采用limit来进行翻页查询,比如limit(0,10)表示列出第一页的1 ...
- 计算机考研压分的学校,篡改分数,恶意压分...考研院校的骚操作大盘点!小心避坑!...
篡改分数,恶意压分...考研院校的骚操作大盘点!小心避坑! 摘要:对考研的同学来说,择校是至关重要的一环.尤其是在往届考生群中,大家讨论最多的就是要不要换学校.一些同学经历了被歧视.专业课压分 作者 ...
- mysql分页时获得行数_MySQL分页取得总行数新法
SELECT语句中经常用到LIMIT限制返回行数有时候可能想要知道如果没有LIMIT会返回多少行,比如做分页的时候,但又不想再执行一次相同语句. 我们要怎么做呢? 如下 在SELECT查询中包含 SQ ...
- 数据库MySQL分页时用的语句
使用limit关键字.Select * from 表名 where 条件 limit 开始位置,结束位置.通过动态的改变开始和结束位置的值来实现分页.
- mysql插入时主键id为uuid_mysql插入数据自动生成主键uuid
DemoMapper.java //注意方法的返回值必须是void; void add(Demo demo); ============================================ ...
- Mysql的避坑---- The error may involve defaultParameterMap #The error occurred while setting parameters
Mysql的避坑---- Mysql 数据库连接添加 allowMultiQueries=true属性 最近做项目时,发现操作数据库时 sql报错,如下: ### Error updating da ...
- mysql分页与分页性能查询优化
为什么80%的码农都做不了架构师?>>> mysql分页就直接使用limit进行操作,limit如果我们直接不加任何处理可能数据大了就会很卡的. 一. 最常见MYSQL最基本的 ...
- Kubernetes HPA 的三个误区与避坑指南
01 前言 Aliware 云计算带来的优势之一便是弹性能力,云原生场景下 Kubernetes 提供了水平弹性扩容能力(HPA),让应用可以随着实时指标进行扩/缩.然而 HPA 的实际工作情况可能和 ...
最新文章
- ABAP-FI常用BAPI
- hbase报错:org.apache.hadoop.hbase.PleaseHoldException: Master is initializing
- redhat 安装Rabbitmq
- Eclipse系列的隐藏宝藏-2019年版
- java容器遍历_高效遍历Java容器详解
- linux shell ls -1 列显示文件
- 关于学习js的Promise的心得体会
- Keli Linux与网络安全(2)——初探Keli
- mysql五日均线代码_通达信均线源码,5日通达信均线公式源码
- vb2008如何连接mysql_VB如何连接ACCESS数据库详解
- python的画图工具有哪些_python实现画图工具
- YUV Alpha Blend 推导过程
- ir2104s的自举电容_有关IR2104的自举电容和NMOS选择问题.docx
- 悠歌“即时”游戏回合文案
- 倒车入库- 通过后视镜调整方向盘
- 计算机会计期中考试,2017会计从业资格考试《会计电算化》基础阶段备考题
- 数据库(笔记)——关系代数以及相关运算
- vue关闭eslint代码检测
- ## 虚幻四引擎学习——初学者
- 备战一年,终于斩获腾讯T3,我坚信成功是可以复制的
热门文章
- 苹果“自研”心不死 仍考虑收购英特尔基带业务
- 继腾讯后 B站又获阿里投资!加速二次元电商商业化
- 2019年新iPhone消息再曝 将会有重大升级!
- XXX packages are looking for funding run `npm fund` for details
- python ConfigParser模块详解
- vue 切换页面没有改变滚动条_VUE建立照片轮播功能
- csredis封装_ASP.NET Core 2.0下使用Redis——基于CSRedis实现
- 【kafka】kafka 启动 Version `123123` is not a valid version
- 【算法】剑指 Offer 24. 反转链表
- 【java】Java实现异步调用方法(jdk1.8)