MySQL LIMIT 和 ORDER BY 优化

news/2025/9/18 14:59:06/文章来源:https://www.cnblogs.com/dbasql/p/19098799

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/907190.shtml

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

相关文章

固态电池革命:我们离“续航焦虑终结者”还有多远?

大家好,我是爱折腾。 最近琢磨着换车,跟大家一样,每天在网上刷各种评测和资讯。刷得多了,就老看到“固态电池”。各种文章都说它是“续航焦虑的终结者”、“下一代电池技术革命”,好像不聊这个就跟不上时代了。 说…

心得

心得关于开发 那种方式才是最佳实践? 有很多种类,很容易导致非常隐蔽的问题比如使用 sessionStorage 进行页面间数据传递 公共状态在获取前被使用的时序问题 页面级组件与其容器的组合方法 全局的错误拦截 路由的文件…

深入解析:深入剖析C++内存模型:超越原子性的多线程编程基石

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

Spring Security 框架 - 教程

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

Android 安卓 困难处理记录 腾讯IM和厂商离线推送难题 点击离线推送无法唤醒APP启动页但某些Service服务和Application被启动

Android 安卓 困难处理记录 腾讯IM和厂商离线推送难题 点击离线推送无法唤醒APP启动页但某些Service服务和Application被启动pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !im…

百度地图如何获取瓦片图

百度地图如何获取瓦片图1.根据百度地图的经度和纬度来获取瓦片图的 x、y坐标值。 使用第三方javascript库,已经有牛人实现了。 tile-lnglat-transform-es6 如果想表现一下自己很牛,也可以自己去根据思路是实现。 使…

Codeforces Round 1051 (Div 2)

cf1051 Div2 ABCD1D2E题解Problem - A. All Lengths Subtraction 思路: 我们希望 n 和 n - 1 相邻,n - 1, n 和 n - 2 相邻 ... 不断往外扩展 所以我们可以维护 l 和 r 表示当前扩展到了哪里 通过判断下一个数是否和…

scheduleAtFixedRate

定时任务中的scheduleAtFixedRate方法 在Java的并发编程中,scheduleAtFixedRate是ScheduledExecutorService接口中的一个方法,用于在给定的初始延迟后,以固定的周期执行所提交的任务。这个方法非常适合需要多次执行…

redis-string类型常用命令

redis-string类型常用命令String类型value是Redis中最常用,最基本的类型,String类型的value可以存放任意类型数据,包括数值型,二进制的图片,音频,视频,序列化对象等等。一个String类型的value最大时521M。 1.se…

CRMEB标准版PHP核销功能深度解析,附权限配置技巧

订单核销,使用核销码或立即核销进行核销 核销订单:用户购买商品时选择到店自提的订单。到店后需要出示核销码以供核销。 1、收入核销码核销 订单—>订单管理—>立即核销在订单列表页,点击左上角订单核销按钮,…

一文详细说明大模型安全评估要怎么做

一文详细说明大模型安全评估要怎么做《网络安全技术 生成式人工智能服务安全基本要求》 《基本要求》是大模型安全总纲性文件,提纲挈领地指出模型备案上线所需具备的基础条件,是大模型备案技术性指导文件《生成式人工…

apache doris 和 clickhouse的区别

Apache Doris 和 ClickHouse 均为 MPP(大规模并行处理)架构的列式存储 OLAP 数据库,核心定位都是解决海量数据下的高性能分析查询场景,但二者在技术设计、生态适配、适用场景等维度存在显著差异。以下从 核心架构、…

Python numba jit加速计算

安装pip install numba使用示例import timefrom numba import jit# 原始函数 def python_sum(n):total = 0for i in range(n):total += ireturn total# Numba 加速版本 @jit(nopython=True) def numba_sum(n):total = …

人机协作开发新体验:花两天时间与Cursor共同打造一个微信小程序

前言 在过去的几天里,我完成了一个完整的微信小程序项目——双色球机选应用。 这个项目的独特之处在于,所有的代码编写工作都是由 Cursor 完成的,而我主要负责需求分析、功能规划和调试测试。项目概述 应用功能 我开…

OEC-Turbo刷群晖Armbian流程记录

记录OEC-Turbo的刷机流程,为以后反复折腾做参考。 设备版本:OEC L2.0,不清楚1.0和2.0的区别 系统:Windows 11 准备工具瑞芯微驱动 瑞芯微烧录工具 Loader文件 固件 镊子 Type-C数据线工具下载链接:https://pan.qu…

01_网络分层模型

一、OSI 七层网络模型 所谓七层就是基于 URL 等应用层信息的负载均衡,四层就是基于 IP + 端口的负载均衡,同样的还有基于二层 MAC 地址,三层 IP 地址的负载均衡。 而 OSI(Open System Interconnection,开放式通信互…

SaaS 是什么?一文带你看懂 SaaS 与传统软件的区别

SaaS 发音类似于「萨斯」,是 Software as a Service 的缩写,直译过来就是「软件即服务」。你可以这样理解: 在 SaaS 模式下,软件变得和水电气很相似,你只需要每月缴纳固定的费用即可享受服务。再举个比较具体的例…

FreeCAD-即时入门-全-

FreeCAD 即时入门(全)原文:zh.annas-archive.org/md5/ba46ce5f33da4fa68df84701f1baaf8a 译者:飞龙 协议:CC BY-NC-SA 4.0前言 FreeCAD 是一个面向工程世界的通用建模工具。与为动画师和艺术家设计的其他建模工具…

UOS统信服务器操作系统V20(1070)安装mysql8.0.41(建议安装glibc2.28版本)

环境:OS:UOS Server 20 统信服务器操作系统V20(1070)mysql:8.0.41 glib.2.17 操作系统下载https://www.chinauos.com/resource/download-server查看系统glibc版本[root@localhost yum.repos.d]# ldd --versionldd (GNU…

MyEMS:重新定义人与能源的关系 —— 一场藏在数据里的能源管理革命

能源,这个推动现代文明运转却始终隐形的主角,正通过数字技术与我们建立全新的对话方式。MyEMS作为开源能源管理系统,正在悄然引领这场变革——它不仅改变我们管理能源的方式,更在重新定义人与能源之间的关系。 从被…