MySQL 查询 limit 100000000, 10 和 limit 10 速度一样快吗?

MySQL 查询 limit 100000000, 10 和 limit 10 速度一样快吗?

在这里插入图片描述

MySQL内部分为server层存储引擎层。一般情况下存储引擎都用innodb。

server层有很多模块,其中需要关注的是执行器是用于跟存储引擎打交道的组件。

执行器可以通过调用存储引擎提供的接口,将一行行数据取出,当这些数据完全符合要求(比如满足其他where条件),则会放到结果集中,最后返回给调用mysql的客户端

两种查询方式。对应 limit offset, size 和 limit size 两种方式。

而其实 limit size ,相当于 limit 0, size。也就是从0开始取size条数据。

也就是说,两种方式的区别在于offset是否为0。

1. 以主键索引的 LIMIT 10 为例

LIMIT 10 查询的是结果集的前 10 行数据。这种情况下,MySQL 只需要扫描并返回前 10 行数据,操作相对简单且快速。

SELECT * FROM table_name LIMIT 10;

server层会调用innodb的接口,在innodb里的主键索引中获取到第0到10条完整行数据,依次返回给server层,并放到server层的结果集中,返回给客户端。

2. 以主键索引的 LIMIT 100000000, 10 为例

LIMIT 100000000, 10 查询的是从结果集的第 100000001 行开始的 10 行数据。这种情况下,MySQL 需要先扫描前 100000000 行数据并丢弃,然后再返回接下来的 10 行数据。这种操作会导致大量的行扫描和丢弃操作,效率很低。

SELECT * FROM table_name LIMIT 100000000, 10;

server层会调用innodb的接口,由于这次的offset=100000000,会在innodb里的主键索引中获取到第0到(100000000+ 10)条完整行数据,返回给server层之后根据offset的值挨个抛弃,最后只留下最后面的size条,也就是10条数据,放到server层的结果集中,返回给客户端。

可以看出,当offset非0时,server层会从引擎层获取到很多无用的数据,而获取的这些无用数据都是要耗时的。

以非主键索引的 LIMIT 10 为例

SELECT * FROM table_name LIMIT 10;

server层会调用innodb的接口,在innodb里的非主键索引中获取到第0条数据对应的主键id后,回表到主键索引中找到对应的完整行数据,然后返回给server层,server层将其放到结果集中,返回给客户端。

而当offset>0时,且offset的值较小时,逻辑也类似,区别在于,offset>0时会丢弃前面的offset条数据。

也就是说非主键索引的limit过程,比主键索引的limit过程,多了个回表的消耗。

但当offset变得非常大时,比如600万,此时执行explain。

可以看到type那一栏显示的是ALL,也就是全表扫描

这是因为server层的优化器,会在执行器执行sql语句前,判断下哪种执行计划的代价更小。

很明显,优化器在看到非主键索引的600w次回表之后,摇了摇头,还不如全表一条条记录去判断算了,于是选择了全表扫描。

因此,当limit offset过大时,非主键索引查询非常容易变成全表扫描。是真性能杀手

性能比较

  • LIMIT 10:MySQL 只需扫描前 10 行数据,快速返回结果,性能高。
  • LIMIT 100000000, 10:MySQL 需要扫描前 100000000 行数据并丢弃,然后返回接下来的 10 行数据,性能低。

优化大偏移量的查询

当你需要从一个大偏移量开始查询时,可以采用以下优化方法:

1. 使用覆盖索引

确保查询使用了覆盖索引,这样可以减少全表扫描的开销。

SELECT col1, col2 FROM table_name FORCE INDEX (index_name) WHERE indexed_column >= value LIMIT 100000000, 10;
2. 通过主键范围查询

使用主键范围查询,先查找主键值,再根据主键值进行查询,避免大偏移量的扫描。

第一步:找到起始主键值
SELECT id FROM table_name ORDER BY id LIMIT 100000000, 1;

-- 假设起始主键值为 start_id
-- 第二步:基于主键值进行查询
SELECT * FROM table_name WHERE id >= start_id LIMIT 10;
3. 使用延迟关联(Deferred Join)

先根据索引字段查找主键,再根据主键进行关联查询,从而避免大偏移量的扫描。

-- 第一步:查找主键值
SELECT id FROM table_name ORDER BY id LIMIT 100000000, 10;

-- 第二步:基于主键进行关联查询
SELECT * FROM table_name WHERE id IN (id1, id2, ..., id10);
4. 使用分页技术

对于用户分页的场景,通常需要记录当前页和页数,采用基于主键或其他唯一标识的分页技术,避免使用 LIMIT 大偏移量查询。

结论

MySQL 中 LIMIT 100000000, 10LIMIT 10 的查询速度并不一样。大偏移量的查询会导致性能问题,可以通过覆盖索引、主键范围查询、延迟关联等方法进行优化。

  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值