MySQL 中 limit 分页偏移量过大的优化
原因
-
查询所有列导致回表 。
-
limit a, b会查询前a+b条数据,然后丢弃前a条数据
优化方案
两种,一般用覆盖索引,使用条件过滤有前提限制。
1. 覆盖索引
所谓的覆盖索引就是从非主聚簇索引中就能查到的想要数据,而不需要通过回表从主键索引中查询其他列,能够显著提升性能。
优化方案就是先查询得到主键id,然后再根据主键id查询其他列数据.
select * from user a join (select id from user where sex = 1 limit 10000000,10) b on a.id = b.id;
上面内容也许有点抽象,解释一下,因为 sex 是有索引,这里命中 sex 索引,而其 data 存储的是 主键值(即 id)那么可以直接得到,所以无需再回表。
回表: 如果查询不是 id 或者 sex ,而是其他字段,那么还要走一遍主索引(即 id 的 B+ 树),得到这个字段的数据。这就是回表。
详细可以看:mysql覆盖索引与回表
关于什么是 非聚簇索引 和 聚簇索引看:MySQL 之 非聚簇索引 和 聚簇索引
2. 条件过滤
基于排序做条件过滤,这样的方式优化是有条件的:主键 id 必须是有序的。在有序的条件下,也可以使用比如创建时间等其他字段来代替主键 id ,但是前提是这个字段是建立了索引的。
一般使用自增主键的时候可以使用这个方式
select * from user where sex = 1 and id > (select id from user where sex = 1 limit 10000000, 1) limit 10;