MySQL limit N offset M 速度慢?来实际体验下

2024-04-11 03:44

本文主要是介绍MySQL limit N offset M 速度慢?来实际体验下,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

直接开始

有一张表:trade_user,表结构如下:


mysql> desc trade_user;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | bigint unsigned  | NO   | PRI | NULL    | auto_increment |
| name       | varchar(20)      | NO   | MUL | NULL    |                |
| email      | longtext         | YES  |     | NULL    |                |
| age        | tinyint unsigned | YES  |     | NULL    |                |
| birthday   | datetime         | YES  |     | NULL    |                |
| created_at | datetime         | YES  |     | NULL    |                |
| updated_at | datetime         | YES  |     | NULL    |                |
| id_no      | char(18)         | NO   |     |         |                |
+------------+------------------+------+-----+---------+----------------+
8 rows in set (0.02 sec)

COPY

表行数


mysql> select count(*) from trade_user;
+----------+
| count(*) |
+----------+
|  3536655 |
+----------+
1 row in set (0.60 sec)

COPY

无索引limit n offset m

OFFSET 0:limit 10 offset 0

 select  * from trade_user order by email limit 10 offset 0;

COPY

执行耗时:1.41 秒

file

OFFSET 1万: limit 10 offset 10000


select  * from trade_user order by email limit 10 offset 10000;

COPY

执行耗时: 1.68秒

file

OFFSET:10万:limit 10 offfet 100000


select  * from trade_user order by email limit 10 offset 100000;

COPY

执行耗时:1.89秒

file

OFFSET:100万:limit 10 offset 1000000


select  * from trade_user order by email limit 10 offset 1000000;

COPY

执行耗时:4.06秒

file

OFFSET:200万:limit 10 offset 2000000


select  * from trade_user order by email limit 10 offset 2000000;

COPY

执行耗时:9.07秒

file

有索引limit n offset m

trade_user表的name列有一个普通索引。

OFFSET 0:limit 10 offset 0

 select  * from trade_user order by name limit 10 offset 0;

COPY

执行耗时:0.01 秒

file

OFFSET 200万:limit 10 offset 2000000

 select  * from trade_user order by name limit 10 offset 2000000;

COPY

执行耗时:7.21 秒

file

为什么?

OFFSET越大,MySQL扫描行数越多:


+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+----------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra          |
+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+----------------+
|  1 | SIMPLE      | trade_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 3447992 |   100.00 | Using filesort |
+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+----------------+
1 row in set, 1 warning (0.00 sec)

COPY


| EXPLAIN| -> Limit/Offset: 10/2000000 row(s)  (cost=359470 rows=10) (actual time=8737..8737 rows=10 loops=1)-> Sort row IDs: trade_user.`name`, limit input to 2000010 row(s) per chunk  (cost=359470 rows=3.45e+6) (actual time=2552..8699 rows=2e+6 loops=1)-> Table scan on trade_user  (cost=359470 rows=3.45e+6) (actual time=0.0247..1870 rows=3.54e+6 loops=1)|
1 row in set (8.74 sec)

COPY

总结

在对大表进行 LIMIT 和 OFFSET 操作时,随着偏移量(OFFSET)的增加,性能会显著下降。由于 MySQL 必须首先跳过 OFFSET 之前的所有行,才能获取到 LIMIT 指定的数据量,因此当 OFFSET 值较大时,这会导致显著的性能开销,尤其是在没有对排序列添加索引的情况下。通过性能测试得出,即使 LIMIT 的值相同,越大的 OFFSET 会使 MySQL 扫描的行数越多,因此执行时间越长。

性能测试的总结如下:

  • 当没有索引支持 ORDER BY 子句时,即使是小范围的 LIMIT 查询,随着 OFFSET 的增加,查询性能会急剧下降。从测试结果来看,相同的 LIMIT 值下,OFFSET 值为 0 时查询耗时为 1.41 秒,而 OFFSET 值为 200 万时耗时增加到了 9.07 秒。
  • 当存在索引支持 ORDER BY 子句时,查询性能显著提升,OFFSET 为 0 时耗时只需 0.01 秒。这表明,有索引的情况下,小 OFFSET 值查询的性能提升非常明显。但即使有索引支持,大 OFFSET 值仍然会导致较高的性能开销,如 OFFSET 值为 200 万时耗时为 7.21 秒。
  • 测试中观察到的性能差异主要是由于 MySQL 在未使用索引的情况下需要对所有数据进行全表扫描,并使用文件排序来找到 ORDER BY 子句中指定的顺序,然后才能跳过 OFFSET 指定的行。

为了优化大表的 LIMIT 和 OFFSET 查询:

  • 避免使用大的 OFFSET 值,特别是在没有对 ORDER BY 的字段进行索引优化的情况下。
  • 考虑使用 "keyset pagination" 或 "seek method" 方法,即通过跟踪上一次检索的最后一个记录的标识,来避免使用 OFFSET
  • 确保 ORDER BY 中的列上有适当的索引以提高排序和检索效率。
  • 尽量减少查询结果中的列数,只取需要的列。
  • 如果有可能,调整应用逻辑以减少数据量,或将常用查询结果进行缓存。

大表不用使用大OFFSET。

参考

MySQL limit N offset M 速度慢?来实际体验下 – 小厂程序员

这篇关于MySQL limit N offset M 速度慢?来实际体验下的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/892988

相关文章

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

MySQL存储过程之循环遍历查询的结果集详解

《MySQL存储过程之循环遍历查询的结果集详解》:本文主要介绍MySQL存储过程之循环遍历查询的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言1. 表结构2. 存储过程3. 关于存储过程的SQL补充总结前言近来碰到这样一个问题:在生产上导入的数据发现

MySQL 衍生表(Derived Tables)的使用

《MySQL衍生表(DerivedTables)的使用》本文主要介绍了MySQL衍生表(DerivedTables)的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学... 目录一、衍生表简介1.1 衍生表基本用法1.2 自定义列名1.3 衍生表的局限在SQL的查询语句select

MySQL 横向衍生表(Lateral Derived Tables)的实现

《MySQL横向衍生表(LateralDerivedTables)的实现》横向衍生表适用于在需要通过子查询获取中间结果集的场景,相对于普通衍生表,横向衍生表可以引用在其之前出现过的表名,本文就来... 目录一、横向衍生表用法示例1.1 用法示例1.2 使用建议前面我们介绍过mysql中的衍生表(From子句

六个案例搞懂mysql间隙锁

《六个案例搞懂mysql间隙锁》MySQL中的间隙是指索引中两个索引键之间的空间,间隙锁用于防止范围查询期间的幻读,本文主要介绍了六个案例搞懂mysql间隙锁,具有一定的参考价值,感兴趣的可以了解一下... 目录概念解释间隙锁详解间隙锁触发条件间隙锁加锁规则案例演示案例一:唯一索引等值锁定存在的数据案例二:

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

MySQL 设置AUTO_INCREMENT 无效的问题解决

《MySQL设置AUTO_INCREMENT无效的问题解决》本文主要介绍了MySQL设置AUTO_INCREMENT无效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录快速设置mysql的auto_increment参数一、修改 AUTO_INCREMENT 的值。

MYSQL查询结果实现发送给客户端

《MYSQL查询结果实现发送给客户端》:本文主要介绍MYSQL查询结果实现发送给客户端方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql取数据和发数据的流程(边读边发)Sending to clientSending DataLRU(Least Rec

MySQL分区表的具体使用

《MySQL分区表的具体使用》MySQL分区表通过规则将数据分至不同物理存储,提升管理与查询效率,本文主要介绍了MySQL分区表的具体使用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、分区的类型1. Range partition(范围分区)2. List partition(列表分区)3. H