深度分页 - MySQL limit 200000会有什么问题

2022-11-14  本文已影响0人  面向对象架构

后端开发中最场景的需求就是分页查询了,那无脑分页就万事大吉了吗?当大数据量查询场景下,如果 limit 200000, 10 会不会有问题呢?

深度分页

limit 200000, 10 到底会不会有问题呢?光说不练假把式,来,操作起来先!

mysql> CREATE TABLE `order_detail` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` varchar(50) NOT NULL DEFAULT '' COMMENT '用户ID',
  `order_id` bigint(20) DEFAULT NULL COMMENT '订单id',
  `sku_id` bigint(20) unsigned NOT NULL COMMENT '商品ID',
  `order_time` datetime DEFAULT NULL COMMENT '下单时间,格式yyyy-MM-dd HH:mm:ss',
  PRIMARY KEY (`id`),
  KEY `idx_time_user` (`order_time`,`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单详情';

执行计划Extra列可能出现的值

  1. Using where:优化器需要通过索引回表查询
  2. Using Index:覆盖索引,即根据索引树可直接检索列信息,无需额外的操作来读取实际的行
  3. Using index condition:索引下推,在MySQL5.6后出现,充分利用了索引中的数据,尽量在查询出整行数据之前过滤掉无效的数据
  4. Backward index scan:对索引列使用了降序操作
  5. Using index for group_by:只查索引列,对索引列使用了 group by
  6. Using filesort:文件排序,一般在 order by 数据量多大时出现,MySQL会将所有数据召回内存中排序,比较消耗资源
  7. using temporary:使用了临时表,一般在使用group by、order by时会遇到
针对limit 100 和 limit 200000 分别执行查询及执行计划(mysql版本:8.0.26): limit优化前

结合上图,同样的语句,不同的偏移量,结果执行计划相差巨大。

这里limit 200000, 10由于limit偏移量过大,引起以下两个问题,进而影响查询性能:

对比上面两个sql的查询时间可知,分页深度越深,就越耗时。第2条sql,每次至少要查询9w多条数据,取其中的1条数据,其余的数据丢失掉,非常耗时,这就是深度分页的问题。

优化方案

针对主键自增型的分页查询优化

限制id法:取上页中最大id,然后根据最大id进行分页查询

mysql> select * from order_detail where id > 200000 limit 10;

优化后的sql执行耗时降低了很多,有明显的效率提升的。
这种方案的限制条件

针对主键非自增型的分页查询优化

很多业务场景,不是通过主键id分页查询的,而是由多个组合条件构成分页查询条件,这种情况下我们可以通过延迟关联来处理。
延迟关联:通过子查询查询出当前页的id,然后再根据当前页id回表查询所需字段。查询当前页id用到了索引,遍历索引树还是很快的。该方案很好的避免了限制id法的使用条件,经常被用于后端的管理平台,来看个具体sql和执行计划:

mysql> select od.id,user_id,order_id,sku_id,order_time from order_detail as od inner join (select id FROM order_detail limit 200000, 10) as b on od.id = b.id;

从执行计划上能看出,子查询用到了覆盖索引,整个过程遍历索引还是很快的。

从业务角度规避深度分页

我们也可以换个角度,既然问题不好解决,那是不是也可以提前规避问题呢?
方法肯定是有的,技术上不好解决,那就通过业务来规避问题。比如,可以采用如下措施:

上一篇 下一篇

猜你喜欢

热点阅读