MySQL 系列:注意 ORDER 和 LIMIT 联合使用的陷阱

文章目录

  • 前言
  • 背后的原因
    • ORDER BY 排序列存在相同值时返回顺序是不固定的
    • LIMIT 和 ORDER BY 联合使用时的行为
    • ORDER BY 或 GROUP BY 和 LIMIT 联合使用优化器默认使用有序索引
  • 如何解决
  • 其它说明
  • 个人简介

前言

  • 不知道大家在在分页查询中有没有遇到过这个问题,分页查询中不同的页中出现了同一条数据,出现了分页错乱的问题:

查询数据源

  • 整体排序:SELECT * from test_1 ORDER BY create_date;

整体排序

  • 提取排序后的前两条:SELECT * from test_1 ORDER BY create_date LIMIT 0,2;

LIMIT 0,2

  • 提取排序后的最后两条:SELECT * from test_1 ORDER BY create_date LIMIT 8,2;

LIMIT 8,2

  • 上面的结果是不是很奇怪,按照大家正常的思考,MySQL 对我们查询的数据进行整体排序,我们按页取出,理论上不应该在不同的页中有相同的数据,下面我们一起来看看隐藏在背后的原因。

背后的原因

  • https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
  • 官网的说明内容比较多,我主要摘抄了以下几点比较相关的内容,下面我们一起来看看吧。

ORDER BY 排序列存在相同值时返回顺序是不固定的

  • 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列中具有相同的值,则服务器可以自由地以任何顺序返回这些行,并且可以根据总体执行计划以不同的方式返回。换句话说,相对于无序列,这些行的排序顺序是不确定的。

LIMIT 和 ORDER BY 联合使用时的行为

  • If you combine LIMIT row_count with ORDER BY, MySQL stops sorting as soon as it has found the first row_count rows of the sorted result, rather than sorting the entire result. If ordering is done by using an index, this is very fast. If a filesort must be done, all rows that match the query without the LIMIT clause are selected, and most or all of them are sorted, before the first row_count are found. After the initial rows have been found, MySQL does not sort any remainder of the result set.
  • 如果你联合使用 LIMIT 和 ORDER BY ,MySQL 会找到所需要的行后尽可能快的返回,而不是对所有满足查询条件的行进行排序。如果使用索引排序,那么速度会非常快;如果使用文件排序,所有满足条件都会被选中(不包括 Limit 条件),这些行的大多数,或全部都会被排序直到满足 Limit 的行数。满足的行数一旦找到,则不会对剩余的数据进行排序。
  • 我们看一下官网的例子:
// 全表排序时
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 |
+----+----------+--------+// 部分排序时
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 |
+----+----------+--------+// 可以看到 MySQL 并没有对所有数据整体排序之后再取数据

ORDER BY 或 GROUP BY 和 LIMIT 联合使用优化器默认使用有序索引

  • For a query with an ORDER BY or GROUP BY and a LIMIT clause, the optimizer tries to choose an ordered index by default when it appears doing so would speed up query execution. Prior to MySQL 5.7.33, there was no way to override this behavior, even in cases where using some other optimization might be faster. Beginning with MySQL 5.7.33, it is possible to turn off this optimization by setting the optimizer_switch system variable's prefer_ordering_index flag to off.
  • 简单来说,5.7.33 以前会默认会选择排序字段的索引,即使存在更快的查询计划;5.7.33 开始我们可以关闭这种优化行为。我们来看一下官网提供的例子:
mysql> CREATE TABLE t (->     id1 BIGINT NOT NULL,->     id2 BIGINT NOT NULL,->     c1 VARCHAR(50) NOT NULL,->     c2 VARCHAR(50) NOT NULL,->  PRIMARY KEY (id1),->  INDEX i (id2, c1)-> );// prefer_ordering_index 开启(默认开启)
mysql> SELECT @@optimizer_switch LIKE '%prefer_ordering_index=on%';
+------------------------------------------------------+
| @@optimizer_switch LIKE '%prefer_ordering_index=on%' |
+------------------------------------------------------+
|                                                    1 |
+------------------------------------------------------+mysql> EXPLAIN SELECT c2 FROM t->     WHERE id2 > 3->     ORDER BY id1 ASC LIMIT 2\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: tpartitions: NULLtype: index
possible_keys: ikey: PRIMARYkey_len: 8ref: NULLrows: 2filtered: 70.00Extra: Using where// prefer_ordering_index 关闭
mysql> SET optimizer_switch = "prefer_ordering_index=off";
mysql> EXPLAIN SELECT c2 FROM t->     WHERE id2 > 3->     ORDER BY id1 ASC LIMIT 2\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: tpartitions: NULLtype: range
possible_keys: ikey: ikey_len: 8ref: NULLrows: 14filtered: 100.00Extra: Using index condition; Using filesort

如何解决

  • 从上面我们可以知道,ORDER 列存在相同字段返回的顺序是不确定,且 LIMIT 和 ORDER BY 联合使用时可能不会对所有行进行排序,我们可以在排序字段中加入一个不存在重复值的列进行辅助排序,那么则不会存在这个问题。
  • 比如在文章开头的案例中我们可以加入 ID 字段进行辅助排序:
  • SELECT * from test_1 ORDER BY create_date,id;

ORDER BY create_date,id

  • SELECT * from test_1 ORDER BY create_date,id LIMIT 0,2;

ORDER BY create_date,id LIMIT 0,2

  • SELECT * from test_1 ORDER BY create_date,id LIMIT 8,2;

ORDER BY create_date,id LIMIT 8,2

  • 可以看到,分页的顺序和我们整体排序的顺序一致,不会出现分页错乱的问题。

其它说明

  • MySQL 版本:
SELECT VERSION();5.7.36-log

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/216983.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通俗易懂:插入排序算法全解析(C++)

插入排序算法是一种简单直观的排序算法,它的原理就像我们玩扑克牌时整理手中的牌一样。下面我将用通俗易懂的方式来解释插入排序算法的工作原理。 假设我们手上有一副无序的扑克牌,我们的目标是将它们从小到大排列起来。插入排序算法的思想是&#xff0…

0基础学习VR全景平台篇第127篇:什么是VR全景/720全景漫游?

“全景”作为一种表现宽阔视野的手法,在很久之前就得到了普遍的认同。北宋年间,由张择端绘制的《清明上河图》就是一幅著名的全景画。摄影术出现后,全景摄影也随之而生。 到今天,全景拍摄不再被专业摄影师所独享,广大…

leetcode--3. 无重复字符的最长子串[滑动窗口\哈希表 c++]

原题 : 3. 无重复字符的最长子串 - 力扣(LeetCode) 题目解析: 最长子串可以用滑动窗口解决,无重复字符可以使用哈希表解决。 算法原理: 滑动窗口哈希表 哈希表作为一个数组存放每个字符出现的次数。 …

06进程间关系-学习笔记

Orphan Process孤儿进程 父进程先于子进程退出,子进程失去托管,这种子进程统称为孤儿进程 失效进程(孤儿进程):导致内存泄漏,影响新进程的创建孤儿进程的危害不可预测,如果一个孤儿进程持续的申…

Spark环境搭建和使用方法

目录 一、安装Spark (一)基础环境 (二)安装Python3版本 (三)下载安装Spark (四)配置相关文件 二、在pyspark中运行代码 (一)pyspark命令 &#xff08…

go自带rpc框架生产环境使用demo

基础使用 序列化使用自带gob协议 server package mainimport ("net""net/rpc" )// 定义一个handler结构体 type HelloService struct { }// 定义handler方法,大小写,参数,返回值都是固定的,否则无法注册 func (receiv…

五、Microsoft群集服务(MSCS)环境的搭建

一、【目的】 学会利用Windows Server布置群集环境。 二、【设备】 FreeNAS11.2,Windows Server 2019 三、【要求】 学会利用Windows Server布置群集环境,掌握处理问题的能力。 配置表: 节点公网IP(public)内网IP(private)群集IP(clust…

vue2-安装elementUI时警告

警告内容&#xff1a;npm WARN deprecated core-js2.6.12: core-js<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up …

JavaScipt验证URL新方法(2023 年版)

JavaScript诞生以来&#xff0c;一直没有一种简单的方法验证URL&#xff0c;现在JavaScript新增了一个新方法——URL.canParse。 URL.canParse(https://www.stefanjudis.com); // true URL.canParse(www.stefanjudis.com); // falseURL.canParse() 是一种快速验证字符串是否为…

改进的A*算法的路径规划(1)

引言 近年来&#xff0c;随着智能时代的到来&#xff0c;路径规划技术飞快发展&#xff0c;已经形成了一套较为 成熟的理论体系。其经典规划算法包括 Dijkstra 算法、A*算法、D*算法、Field D* 算法等&#xff0c;然而传统的路径规划算法在复杂的场景的表现并不如人意&#xf…

【网络协议】LACP(Link Aggregation Control Protocol,链路聚合控制协议)

文章目录 LACP名词解释LACP工作原理互发LACPDU报文确定主动端确定活动链路链路切换 LACP和PAgP有什么区别&#xff1f;LACP与LAG的关系LACP模式更优于手动模式LACP模式对数据传输更加稳定和可靠LACP模式对聚合链路组的故障检测更加准确和有效 推荐阅读 LACP名词解释 LACP&…

【论文笔记】Gemini: A Family of Highly Capable Multimodal Models——细看Gemini

Gemini 【一句话总结&#xff0c;对标GPT4&#xff0c;模型还是transformer的docoder部分&#xff0c;提出三个不同版本的Gemini模型&#xff0c;Ultra的最牛逼&#xff0c;Nano的可以用在手机上。】 谷歌提出了一个新系列多模态模型——Gemini家族模型&#xff0c;包括Ultra…

Cocos Creator:创建棋盘

Cocos Creator&#xff1a;创建棋盘 创建地图三部曲&#xff1a;1. 创建layout组件2. 创建预制体Prefab&#xff0c;做好精灵贴图&#xff1a;3. 创建脚本LayoutSprite.ts收尾工作&#xff1a; 创建地图三部曲&#xff1a; 1. 创建layout组件 使用layout进行布局&#xff0c;…

云贝教育 |【分享课】12月14日周四PostgreSQL分享主题:PG的流复制

分享主题&#xff1a;PG的流复制 讲师&#xff1a;刘峰 时间&#xff1a;12月14日 周四 晚上 19:30 分享平台&#xff1a;微信视频号 云贝学院 分享内容&#xff1a; 流复制的工作原理流复制主从搭建流复制主从切换流复制添加/删除备节点流复制修改同步模式

【面试经典150 | 二叉树】对称二叉树

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;递归方法二&#xff1a;迭代 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的…

产品经理必掌握自定义元件流程图泳道图

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a; 《产品经理管理项目周期及【Axure RP9】简介&安装&基本使用》 ⛺️ 越努力 &#xff0c;越幸运 目录 一、什么是自定义元件 1.1如何自定义元件 二、什么是流程图 &…

软件设计原则:耦合与内聚

目录 什么是耦合&#xff1f; 耦合的定义 类型和影响 什么是内聚&#xff1f; 内聚的定义 类型和优点 耦合与内聚的平衡 结语 在软件开发中&#xff0c;良好的设计是构建可维护、可扩展和可理解的系统的关键。耦合和内聚是软件设计中两个至关重要的概念&#xff0c;它们…

教你用JMeter做接口测试的几个简单实例

前言 这次小项目是基于HTTP协议的接口&#xff0c;通过JMeter来完成一次基本的接口测试&#xff0c;完整复习一下JMeter的基本操作。 在实际项目中&#xff0c;测试也要先从开发那拿到接口说明书&#xff0c;分析熟悉业务后&#xff0c;写接口的测试用例&#xff0c;最后再在…

springboot框架的客制化键盘个性化商城网站

客制化键盘网站是从客制化键盘的各部分统计和分析&#xff0c;在过程中会产生大量的、各种各样的数据。本文以客制化键盘管理为目标&#xff0c;采用B/S模式&#xff0c;以Java为开发语言&#xff0c;Jsp为开发技术、idea Eclipse为开发工具&#xff0c;MySQL为数据管理平台&am…

MyBatis 四大核心组件之 ResultSetHandler 源码解析

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…