小弟新写了一个功能,自测和测试环境测试都没问题,但在生产环境会出现偶发问题。于是,加班到12点一直排查问题,终于定位了的问题原因:Mysql Limit查询优化导致。现抽象出问题模型及解决方案,分析给大家,避免大家踩坑。

问题场景

新上线一个交易记录导出功能,逻辑很简单:根据查询条件,导出对应的数据。由于数据量比较大,在查询数据库时采用了分页查询,每次查询1000条数据。

自测正常,测试环境正常,上线之后运营反馈导出的数据有重复记录

原本是以为业务逻辑问题,重新Review了一遍代码,依旧未找到问题原因。最后只好把SQL语句拿出来单独执行,导出数据,对比发现竟然是SQL语句查询结果乱序导致的。

原因分析

查询语句以create_time进行倒序排序,通过limit进行分页,在正常情况下不会出现问题。但当业务并发量比较大,导致create_time存在大量相同值时,再基于limit进行分页,就会出现乱序问题。

出现的场景是:以create_time排序,当create_time存在相同值,通过limit分页,导致分页数据乱序

比如,查询1000条数据,其中有一批create_time记录值都为”2021-10-28 12:12:12“,当创建时间相同的这些数据,一部分出现在第一页,一部分出现在第二页,在查询第二页的数据时,可能会出现第一页已经查过的数据。

也就是说,数据会来回跳动,一会儿出现在第一页,一会儿出现在第二页,这就导致导出的数据一部分重复,一部分缺失。

查看了Mysql 5.7和8.0的官方文档,描述如下:

If multiple rows have identical values in the ORDER BY columns, the server is free to return those rows in any order, and may do so differently depending on the overall execution plan. In other words, the sort order of those rows is nondeterministic with respect to the nonordered columns.

上述内容概述:在使用ORDER BY对列进行排序时,如果对应(ORDER BY的列)列存在多行相同数据,(Mysql)服务器会按照任意顺序返回这些行,并且可能会根据整体执行计划以不同的方式返回

简单来说就是:ORDER BY查询的数据,如果ORDER BY列存在多行相同数据,Mysql会随机返回。这就会导致虽然使用了排序,但也会发生乱序的状况。

解决方案

针对上述问题,基本的解决思路是:避免ORDER BY列的值出现重复。因此,可以加入其他维度,比如ID等其他排序列。

select * from tb_order order by create_time ,id desc;

这样,在create_time相同时,会根据id进行排序,而id肯定是不同的,就再不会出现上述问题了。

拓展知识

其实,上述内容在Mysql的官网已经有明确说明,而且还举了例子。下面对官网的内容和例子做一个简单的汇总总结。

limit查询优化

如果我们只是查询一个结果集的一部分,那么不要查询所有数据,然后再丢弃不需要的数据,而是要通过limit条件来进行限制。

在没使用having条件时,Mysql可能会对limit条件优化:

  • 如果只查询几条数据,建议使用limit,这样Mysql可能会用到索引,而通常情况下Mysql是全表扫描;

  • 如果将limit row_countorder by结合使用,Mysql会在找到第一个row_count结果集后立刻停止排序,而不是对整个结果集进行排序。如果此时基于索引进行操作,速度会更快。如果必须进行文件排序,在找到row_count结果集之前,会对部分或所有符合条件的结果进行排序。但当找到row_count结果之后,便不会对剩余部分进行排序了。这种特性的一个表现就是我们前面提到的带有limit和不带limit进行查询时,返回的结果顺序可能不同。

  • 如果将limit row_countdistinct结合使用,Mysql会在找到row_count结果集唯一行后立马停止。

  • 在某些情况下,可以通过按照顺序读取索引(或对索引进行排序),然后计算摘要直到索引变化来实现group by。在这种情况下,limit row_count不会计算任何不必要的group by值。

  • 一旦MySQL向客户端发送了所需数量的行,就会中止查询,除非使用了SQL_CALC_FOUND_ROWS。在这种情况下,可以使用 SELECT FOUND_ROWS() 检索行数。

  • LIMIT 0会快速返回一个空集合,通常可用于检查SQL的有效性。还可以用于在应用程序中获得结果集的类型。在Mysql客户端中,可以使用--column-type-info来显示结果列类型。

  • 如果使用临时表来解析查询,Mysql会使用 limit row_count来计算需要多少空间。

  • 如果order by未使用索引,且存在limit条件,则优化器可能会避免使用合并文件,而采用内存filesort操作对内存中的行进行排序。

了解了limit的一些特性,下面再回到本文的重点,limit row_countorder by结合使用特性。

limit与order by结合使用

在上面第二条中已经提到,limit row_countorder by结合呈现的特性之一就是结果返回的顺序是不确定的。而影响执行计划的一个因素就是limit,因此带有limit与不带有limit执行同样的查询语句,返回结果的顺序可能不同。

下面示例中,根据category列进行排序查询,而id和rating是不确定的:

mysql> SELECT * FROM ratings ORDER BY category;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
|  2 |        3 |    5.0 |
|  7 |        3 |    2.7 |
+----+----------+--------+

当查询语句包含limit时,可能会影响到category值相同的数据:

mysql> SELECT * FROM ratings ORDER BY category LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  4 |        2 |    3.5 |
|  3 |        2 |    3.7 |
|  6 |        2 |    3.5 |
+----+----------+--------+

其中id为3和4的结果位置发生了变化。

在实践中,保持查询结果的顺序性往往非常重要,此时就需要引入其他列来保证结果的顺序性了。当上述实例引入id之后,查询语句及结果如下:

mysql> SELECT * FROM ratings ORDER BY category, id;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
|  2 |        3 |    5.0 |
|  7 |        3 |    2.7 |
+----+----------+--------+mysql> SELECT * FROM ratings ORDER BY category, id LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
+----+----------+--------+

可以看出,当添加了id列的排序,即使category相同,也不会出现乱序问题。这正与我们最初的解决方案一致。

小结

本来通过实践中偶发的一个坑,聊到了Mysql对limit查询语句的优化,同时提供了解决方案,即满足了业务需求,又避免了业务逻辑的错误。

很多朋友都在使用order by和limit语句进行查询,但如果不知道Mysql的这些优化特性,很可能已经入坑,只不过数据量没有触发呈现而已。

如果这篇文章帮到你了,关注一波,后续更多实战干货分享。

Mysql官方文档:https://dev.mysql.com/doc/refman/8.0/en/limit-optimization.html

往期推荐

List 去重的 6 种方法,这个方法最完美!

面试官:重写 equals 时为什么一定要重写 hashCode?

面试官:final、finally、finalize 有什么区别?

不知道Mysql排序的特性,加班到12点,认了认了!相关推荐

  1. Mysql排序的特性详情

    文章来源: 学习通http://www.bdgxy.com/ 目录 1.问题场景 2.原因分析 3.解决方案 4.拓展知识 4.1 limit查询优化 4.2 limit与order by结合使用 5 ...

  2. mysql排序显示行数的语句_MySQL中sql语句count(*),orderby,随机数据展示。

    count(*)这么慢,我该怎么办? MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高: 而 InnoDB 引擎就麻烦了,它执行 count ...

  3. 会mysql不会sql_不是吧,不会有人还不知道MySQL中具实用的SQL语句

    原标题:不是吧,不会有人还不知道MySQL中具实用的SQL语句 目录 实用的SQL 1.插入或替换 2.插入或更新 3.插入或忽略 4.SQL中的if-else判断语句 5.指定数据快照或备份 6.写 ...

  4. [C语言] 插入排序之希尔(shell)排序的特性及实现

    [C语言] 插入排序之希尔(shell)排序的特性及实现 1.算法特性 希尔排序法又称缩小增量法,由直接插入排序改进而来,是一种不稳定的插入排序方法.其本质上是一种分组排序方法,不需要大量的辅助空间, ...

  5. MySQL笔记--MySQL排序查询(6)

    MySQL排序查询 进阶三:排序查询 案例1:查询员工信息,要求工资从高到低排序 案例2:查询部门编号>=90的员工信息,按入职时间的先后顺序进行排序 案例3:按年薪的高低显示员工信息和年薪[按 ...

  6. 在mysql 服务器上安装sysbench-0.4.12,报错。

    下载可以到csdn.net上下载. 其他环境介绍: 1.rhel6.3 x64,最小化安装 2.mysql 5.5.40 安装步骤: tar xzvf  tar -xzvf sysbench-0.4. ...

  7. 如果不知道MySQL当前使用配置文件(my.cnf)的路径的解决方法

    如果不知道MySQL当前使用配置文件(my.cnf)的路径的解决方法 参考文章: (1)如果不知道MySQL当前使用配置文件(my.cnf)的路径的解决方法 (2)https://www.cnblog ...

  8. MySQL从入门到精通50讲(八)-MySQL排序分组

    前言 声明:以下是博主精心整理的机器学习和AI系列文章,博主后续会不断更新该领域的知识: 人工智能AI实战系列代码全解析 手把手教你ML机器学习算法源码全解析 有需要的小伙伴赶紧订阅吧. MySQL ...

  9. MySQL的索引特性

    MySQL的索引特性 文章目录 MySQL的索引特性 1. 基本原理 2. 创建索引 2.1 创建主键索引 2.2 唯一索引的创建 2.3 普通索引的创建 2.3 全文索引的创建 3. 查询索引 4. ...

最新文章

  1. 魔改ResNet反超Transformer再掀架构之争!作者说“没一处是创新”,这些优化trick值得学...
  2. 进程管理3--经典的进程同步问题
  3. 切换分支 更改只影响当前分支代码_idea 中分支管理操作的意思
  4. STM32中断优先级的管理(NVIC)
  5. Pearson相关系数 - Pearson's Correlation Coefficient
  6. xp/win 7 系统搭建 Java环境
  7. 点这里,关注计算机视觉技术最前沿~
  8. 7-2 简单计算器 (13 分)
  9. Wysistat与Webtrends比较
  10. Struts2的OGNL表达式
  11. 电子科技大学成都学院计算机考研,电子科大成都学院又双叒叕现学霸寝室,室友全考上研究生...
  12. 一句话木马上传常见的几种方法
  13. 香港希玛眼科集团第二届眼科精准医疗国际会议在京启幕
  14. 【genius_platform软件平台开发】第七十九讲:Linux系统中可执行程序后台运行的几种方式
  15. performance 优化
  16. 大数据应用导论 Chapter1 | 大数据技术与应用概述
  17. 软件工程心得之——产品经理与项目经理的区别
  18. Android面试必过——Android常见的问题
  19. linux中如何查看文件上下文,linux通过grep根据关键字查找日志文件上下文
  20. Word转PPT怎么转换最简单?

热门文章

  1. oracle的undo表空间不足,undo表空间不足,ORA-30036 unable to extend segment by ...
  2. 获取Linux内存、cpu、磁盘IO等信息
  3. MySQL:基本命令
  4. python练习笔记——利用信号signal处理僵尸进程
  5. Flask+uwsgi+Nginx环境搭建
  6. 少年开始学习c#编程,过路的大神请担待!
  7. android点滴27:R文件无法加载 R cannot be resolved to a v...
  8. SQL SERVER 2005 T_SQL新的特性以及解决并发
  9. java已被弱化签名,高效Java第四十条建议:谨慎设计方法签名
  10. jquery动态绑定事件的方法_Jquery绑定事件及动画效果