MySQL LIMIT 和 ORDER BY 优化详解

news/2025/9/18 20:46:52/文章来源:https://www.cnblogs.com/ataoxz/p/19099684

MySQL LIMIT 和 ORDER BY 优化详解

MySQL LIMIT 子句

MySQL LIMIT 子句是控制 SELECT 语句返回行数的重要工具。通过指定从结果集中获取的最大行数,它可以让你处理数据子集,尤其是在涉及大表的情况下。该功能可提高查询性能,并通过只获取必要的行来优化资源使用。

 

MySQL LIMIT 子句的语法

MySQL 中的 LIMIT 子句接受一个或两个参数:偏移量和计数。这两个参数都应该是非负整数。

·偏移量参数表示要从结果集中返回的第一条记录的位置,决定了在返回记录之前要跳过的记录数。

·计数参数指定要从结果集中检索的最大行数,为要返回的行数设置限制。

 

使用两个参数时,第一个参数代表偏移量,第二个参数代表计数。这样就可以从结果集中检索特定范围的记录。但如果只使用一个参数,则表示从结果集开始返回的记录数。

 

LIMIT 子句的基本语法如下:

1
2
3
SELECT column1, column2, ...
FROM table_name
LIMIT offset, count;

 

如何在查询中使用 ORDER BY 和 LIMIT 子句

在对大数据集进行排序的交互式应用程序中,MySQL ORDER BY 带 LIMIT 是 ORDER BY 最常见的用法。在许多网站上,你会发现热门标签、最近注册的用户等,这通常需要在后端使用带 LIMIT 的 ORDER BY。一般来说,这种 ORDER BY 类型看起来像 SELECT ..... WHERE [conditions] ORDER BY [sort] LIMIT N, M。

 

确保使用索引。在执行带 LIMIT 的 ORDER BY 时,不对整个结果集进行扫描和排序是非常重要的,因此必须使用索引--在这种情况下,将启动索引范围扫描,并在产生所需数量的记录后立即停止查询执行。

 

MySQL LIMIT 子句示例

下面我们来看几个如何使用 MySQL LIMIT 子句检索特定结果的示例,包括创建日期、类别 ID 和在多列上运行查询。

 

使用 MySQL LIMIT 10 按 "date_created"和 "category_id"查找结果集

例如,如果我执行 SELECT * FROM sites ORDER BY date_created DESC LIMIT 10,我将使用 (date_created) 上的索引快速获得结果集。

 

现在,如果我使用类似 SELECT * FROM sites WHERE category_id=5 ORDER BY date_created DESC LIMIT 10 的方法;

在这种情况下,通过 date_created 索引也可以工作,但它可能不是最有效的--如果是一个罕见的类别,可能要扫描表的大部分内容才能找到 10 条记录。因此,以 (category_id, date_created) 为索引会更好。

 

让我们来看看更复杂的情况: SELECT * FROM sites WHERE category_id in (5,10,12) ORDER BY date_created DESC LIMIT 10;

尽管看起来与前一个案例非常相似,但由于列表中有多个 category_id 值,因此不能直接使用(category_id、date_created)上的索引,这一点有很大不同。单独使用 date_created 索引仍然有效。从性能角度来看,使用 UNION 解决方法是不错的(尽管有点难看)。

 

在多列查询中使用 MySQL LIMIT

如果应用可以在许多不同列上执行搜索,但选择性却不尽如人意,该怎么办?各种社交网络和交友网站就是此类查询的完美示例。

1
2
3
4
SELECT FROM people
where gender='m' and age between 18 and 28 and country_id=5 and city_id=345
order by last_online desc
limit 10;

限制因素可能有很多,而且都是可选的。这是一个很难解决的问题,可以开发高端的定制搜索解决方案,但如果我们坚持使用简单的 MySQL,在大多数选择性列上使用多个索引将是提高此类查询性能的一个好主意。

例如,可以在(gender,last_online)和(country_id,city_id,last_online)上建立索引,前者假定大多数人会指定性别,后者假定大多数情况下会指定这些。在这种情况下,需要对实际运行的查询和数据选择性进行仔细研究,才能得出一套好的索引,将来也可能需要进行调整。

如果没有通过索引解析的完整 WHERE 子句,则需要注意的主要问题是需要扫描多少行才能解析 order by(这可以在慢查询日志中或通过检查 Hander 统计数据找到)。如果只需检查 50 条记录就能提供 10 行结果集,那么情况还算不错。但如果是 5000 行,则可能需要重新考虑索引。

 

 

此外,请注意:根据特定的常量和其他因素,为提供结果集而扫描的记录数量将是动态的。

 

例如,在我们的示例中,如果我们只使用 (last_online) 索引并查找来自美国的人,那么如果这个国家很小,或者来自这个国家的成员很少(例如斯洛文尼亚),我们可能很快就能找到十个人。

在上面的示例中,我们按最后一列排序。事实上,如果按前导列排序,索引也可用于 ORDER BY。但请注意,用于按列排序的列之后的列不能用于限制结果集。例如

key(a,b,c) SELECT * FROM tbl WHERE c=5 ORDER BY a,b limit 10 - 在这种情况下,可以使用索引中的前两列来满足order by,但索引不会帮助检查 c=5(除非是索引覆盖的查询)。在 (c,a,b) 上建立索引对上述查询更有效。

使用MySQL limit子句的最佳实践

不要按表达式排序

我想这是显而易见的--表达式或函数会阻止索引在 "按......排序 "时的使用。

按驱动表中的列排序

如果使用带 ORDER BY ... LIMIT 的 JOIN,则应尽量使排序列位于驱动表中。有时,这意味着要打破规范化,并在其他表中重复 ORDER BY 要使用的列。

 

下面是一个 ORDER BY 由第二个表完成的示例,它需要文件排序:

1
2
3
4
5
6
7
8
mysql> explain select test.i from test, test t where test.k=5 and test.i=t.k order by t.k limit 5;
+----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref         | rows | Extra                           |
+----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+
|  1 | SIMPLE      | test  | ref  | PRIMARY,k     | k    | 4       | const       |    1 | Using temporary; Using filesort |
|  1 | SIMPLE      | t     | ref  | k             | k    | 4       | test.test.i |    1 | Using where; Using index        |
+----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+
rows in set (0.00 sec)

但是,如果第一张表的访问类型是 "const"或 "system",那么它就会从连接执行中有效地移除(替换为常量),这样,即使 ORDER BY 由第二张表完成,也可以对其进行优化:

1
2
3
4
5
6
7
8
mysql> explain select test.i from test, test t where test.i=5 and test.k=t.k order by t.k limit 5;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | test  | const | PRIMARY,k     | PRIMARY | 4       | const |    1 |             |
|  1 | SIMPLE      | t     | ref   | k             | k       | 4       | const |    1 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
rows in set (0.01 sec)

这里的区别是:“i”是主键,而“k”只是索引列。

注意:在某些情况下,即使可以使用索引来执行带 JOIN 的 ORDER BY,MySQL 仍然无法使用它,因为优化器还不够智能,无法检测到这种情况:

1
2
3
4
5
6
7
8
mysql> explain select test.i from test, test t where test.k=5 and test.i=t.k order by test.k,t.j limit 5;
+----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref         | rows | Extra                           |
+----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+
|  1 | SIMPLE      | test  | ref  | PRIMARY,k     | k    | 4       | const       |    1 | Using temporary; Using filesort |
|  1 | SIMPLE      | t     | ref  | k             | k    | 4       | test.test.i |    1 | Using where; Using index        |
+----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+
rows in set (0.00 sec)

在这种情况下,表上有索引 (k,j),因此可以在每个表上使用索引来优化排序,或者至少可以对第二个表的每个 t.k=const 值使用局部排序。但这并没有做到。

单个方向排序

如果使用 ORDER BY col1, col2,可以使用索引进行优化。如果使用 ORDER BY col1 DESC、col2 DESC,情况也一样,但如果使用 ORDER BY col1、col2 DESC,MySQL 就必须使用文件排序。经典的解决方案是建立适当排序的索引(按 col1 升序,按 col2 降序),但 MySQL 目前还做不到。目前可以使用的变通方法是单独列保存反向值,这样就可以用 ORDER BY col1, col2_reverse 代替。

小心大的 LIMIT

如果需要对前几条记录进行排序,那么使用索引排序的效率会很高,即使需要进行一些额外的过滤,因此通过索引扫描的记录也会比 LIMIT 要求的多。但是,如果处理的 LIMIT 查询偏移量较大,效率就会受到影响。LIMIT 1000,10 可能比 LIMIT 0,10 慢得多。诚然,大多数用户不会浏览超过 10 页的结果。但是,搜索引擎机器人很可能会这样做。在我的项目中,我就看到过机器人在查看 200 多页。此外,许多网站都没有注意到这一点,这就为发起 DOS 攻击提供了一个非常简单的任务--从很少的连接中获取大量的请求,这就足够了。如果你不做其他任何事情,请确保你阻止了页码过大的请求。

 

在某些情况下,例如,如果结果是静态的,可能需要预先计算结果,以便查询它们的位置。因此,您可以用 WHERE 位置在 1000 和 1009 之间来代替 LIMIT 1000,10 查询,这样对任何位置(只要有索引)都有相同的效率。

必要时强制索引

在某些情况下,MySQL 优化器可能更倾向于使用不同的索引,它具有更好的选择性或只是更好的估计,而不是支持你进行排序的索引。例如,在查询 SELECT * FROM people WHERE country_id=5 and city_id=6 order by last_online desc limit 10 时,如果在(country_id,city_id)上有索引,在(country_id,last_online)上也有索引,那么即使会导致文件排序,也可能会选择第一个索引。

要解决这个问题,要么扩展你的索引,这样 MySQL 优化器就不必在更好的排序和更好的查找之间做出选择,要么使用 FORCE INDEX 强制它使用适当的索引。

 

 

对于 "SELECT ... WHERE [conditions] ORDER BY [sort] LIMIT N "这样的查询,优化器可能会选择索引来解决 ORDER BY,而不是在 WHERE 子句中的列上使用索引。在 MySQL 5.7 中修复了一个bug。


对于将 ORDER BY 与 LIMIT 结合在一起的查询,优化器可能会切换到适用于 ORDER BY 的索引。在某些情况下,切换的决定基于启发式而非成本。现在,优化器会统一根据成本来决定是否切换。当切换会导致查询读取整个索引或索引的大部分来查找符合条件的行时,这将会带来更好的性能。

 

使用降序索引

MySQL 8.0 引入了降序索引,按降序存储索引的键值。降序索引可以按正向顺序扫描,这样效率更高。如果查询混合了 ASC 和 DESC,那么如果列上的索引也使用了相应的升序和降序混合列,优化器就可以使用该索引:

1
2
SELECT FROM test
ORDER BY DESC, j ASC

如果 k 是降序列,j 是升序列,优化器可以在 (k, j) 上使用索引。如果 k 是升序,j 是降序,优化器还可以在这些列上使用索引(使用后向扫描)。

 

如果多条记录的 ORDER BY 列中的值相同,服务器可按任意顺序返回这些记录。如果必须确保有 LIMIT 和无 LIMIT 时的记录顺序相同,可在 ORDER BY 子句中包含额外的列,使顺序具有确定性。

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

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

相关文章

python 架构专业的技术50

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

[论文笔记/评估方法] RELIABLE AND DIVERSE EVALUATION OF LLM MEDICAL KNOWLEDGE MASTERY

RELIABLE AND DIVERSE EVALUATION OF LLM MEDICAL KNOWLEDGE MASTERY该文章于2025年发表在ICLR(CCF A),早在2024年9月发布在arxiv。 文章地址:Reliable and Diverse Evaluation of LLM Medical Knowledge Mastery …

本地VMware Workstation Pro的rhel-server-7.9-x86_64服务器配置本地源

1. 安装好VMware Workstation Pro以及rhel-server-7.9-x86_64-dvd.iso后 2. 先对VMware Workstation 进行虚拟机关机 3. 对虚拟机的CD/DVD(SATA) 勾选设备状态为启动时连接,以及连接中勾选使用ISO镜像文件,为本地的r…

SCPI 标准命令

SCPI 标准命令*IDN? 是 SCPI 标准命令之一,用来返回仪器的身份信息。 📌 背景SCPI(Standard Commands for Programmable Instruments,标准可编程仪器命令)是 1990 年制定的一套通用指令集,几乎所有可编程仪器(…

前端,真的让我深刻感受到信息闭塞的恐怖 - 指南

前端,真的让我深刻感受到信息闭塞的恐怖 - 指南2025-09-18 20:34 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display…

05-条件查询

05-条件查询$(".postTitle2").removeClass("postTitle2").addClass("singleposttitle");介绍 通常在进行查询操作的时候,都是查询符合某些条件的数据,很少将表中所有数据都取出来。怎…

2025年十大AI网站构建工具:专家评测与推荐!

2025年,软件开发领域迎来一个关键转折点。随着 AI 技术的飞速发展,传统的网站或应用构建障碍正逐渐消失。市场上涌现出大量功能强大的工具,每一个都号称是您所需要的最佳 AI网站构建器 或 网站生成器。 然而,对于开…

扫描线乱谈

扫描线乱谈前置知识 离散化,线段树 扫描线 首先假设你有n个矩形。如果直接暴力求解这些矩形的覆盖面积肯定不行,这时就要用扫描线算法。 假设有一根线,从下往上扫描:把每个小矩形分成很多不同的块,高是扫过的距离…

详细介绍:量子计算学习(第十四周周报)

详细介绍:量子计算学习(第十四周周报)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "M…

视频播放时切出页面视频暂停(亲测可用)

视频播放时切出页面视频暂停(亲测可用)谷歌浏览器方法:视频播放网页,右键—检查—Elements—Event Listeners—找到blur,点开小三角,remove掉所有子元素

VulkanAPI细节梳理1

1. PSOPipeline State Object,管线状态对象)? PSO 是 Vulkan 的核心概念之一,它是一个包含了渲染所需几乎所有状态的、不可变的对象。你可以把它想象成一台高度可配置的工业机器(GPU)的完整配置方案。在传统 API…

Win11 安装 MinGW

下载:https://github.com/niXman/mingw-builds-binaries/releases或者: 链接: https://pan.baidu.com/s/18nbkKpwnbrNenan9LLEUCA?pwd=twym 提取码: twym解压出来:添加环境变量:验证:

Base match

Humans CAN NOT learn anything MORE if humans are always hyper-intelligent-er or supercalifragilisticexpialidocious-er than others.The tag is biology so the base is the base. Watson-Crick pairing experi…

Polars return_type类型设置(KIMI)

Polars return_type类型设置(KIMI)本文为和KIMI的对话记录,仅供参考:Polars中map_elements返回类型可以设置哪些? User: polars中map_elements中有哪些return type可以设置? Kimi: 在 polars 中,map_elements 的…

意大利 公证 海牙认证速度 单号 双号

支付宝小程序 领事服务中心 那里(对应北京的领事) 比较慢,审核要一周,邮寄过去再寄回来又要一周。总共两周。可以接受单号 微信 山东外事 小程序 (对应济南的领事,只接受山东内的公证)审核很快,一天就审核通过…

Linux命令学习笔记

cd命令 1.切换上级目录 cd ..2.切换到当前用户主目录 cd ~ 3.切换上两级目录 cd ../..4.进入当前目录 cd . cat命令 1.查看文件 cat test.txt 2.查看文件并展示行号空行展示 cat -n test.txt 3.查看文件并展示行号,…

网络安全需要真正的承诺而非表面功夫

本文探讨企业网络安全的核心问题——真正的组织承诺。作者指出许多企业仅采取半吊子安全措施,强调网络安全需要从企业文化到软件开发方式的全面变革,而非依赖外部工具或培训。文章分析了安全厂商解决方案的局限性,并…

详细介绍:(附源码)基于Web的《药谷奇遇记》网站设计与实现-计算机毕设 72940

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

想成为AI绘画高手?打造独一无二的视觉IP!Seedream 4.0 使用指南详解,创意无界,效率翻倍!

想成为AI绘画高手?打造独一无二的视觉IP!Seedream 4.0 使用指南详解,创意无界,效率翻倍!想成为AI绘画高手?打造独一无二的视觉IP!Seedream 4.0 使用指南详解,创意无界,效率翻倍! AI-Compass 致力于构建最全面…

Python拼接协程的运行结果,平铺成一个序列(KIMI)

Python拼接协程的运行结果,平铺成一个序列(KIMI)本文为和KIMI的对话记录,仅供参考。协程结果平铺成序列 User: Python中想要把异步函数返回的列表拼接起来可以这么写吗? flags = await itertools.chain.from_iter…