尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

MySQL LIMIT 和 ORDER BY 优化

MySQL LIMIT 和 ORDER BY 优化
📅 发布时间:2026/7/22 9:37:39

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        |
+----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+
2 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 |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
2 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        |
+----+-------------+-------+------+---------------+------+---------+-------------+------+---------------------------------+
2 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 k DESC, j ASC;

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

 

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

相关新闻

  • Android 安卓 困难处理记录 腾讯IM和厂商离线推送难题 点击离线推送无法唤醒APP启动页但某些Service服务和Application被启动
  • redis-string类型常用命令
  • apache doris 和 clickhouse的区别

最新新闻

  • 【2026-07】陕西汉中快速卷帘门不错的工厂哪个好?硬质卷帘门、硬质快速卷帘门优选——晟世佳品门窗 - 多才菠萝
  • 合肥瑶海 0-6 岁早教去哪?红黄蓝两大旗舰成长中心,测评 + 系统早教一站式育儿 - 博客万
  • YOLOv8优化实现高效有机果蔬智能检测系统
  • 免费纪录片《Java 故事:官方纪录片》上线,回溯 30 年编程语言兴衰历程
  • 魔兽世界字体合并工具:3步解决游戏乱码问题
  • 深入GPIO寄存器操作:从芯片手册到高效嵌入式开发实践

日新闻

  • AI云原生实战05-金融AI上云最难的不是技术,是“不出事“——TCE银行风控架构拆解
  • 2026年GEOSEO优化公司选型深度测评:五大硬核标准严选,这六家重塑搜索增长新格局 - 品牌前沿专家
  • **核验!2026年7月卡地亚香港**售后网点地址及服务电话公告 - 卡地亚服务中心

周新闻

  • SaaS软件行业GEO实践:AI搜索时代的品牌可见性与获客新路径
  • 什么是PCTFE?医药高端包装的“防潮王牌“材料
  • 【JVM调优实战】16-可视化利器-JConsole-VisualVM-JMC

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号