【无标题】

MySQL 深分页问题

MySQL 深分页问题

日常业务开发时,难免会遇到分页问题,按传统方式都是用limit来操作。当翻页过多的时候,就不得不面的深分页问题,导致查询性能急剧下降。

limit 深分页为什么会变慢

  • 先准备一张实验用表
CREATE TABLE `tbl_user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) DEFAULT NULL COMMENT '姓名',
  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB COMMENT='用户表';

然后向数据表中插入100w条记录;当我们查询第一页的时候,速度很快,不到0.01秒就返回了

select * from tbl_user 
where create_time>'2022-07-04' 
limit 0,10;

当如果要翻到底10000页(每页10条)的时候,查询性能急剧下降,耗时0.16s

select * from tbl_user 
where create_time>'2022-07-04' 
limit 10000,10;

耗时问题分析

那么耗时主要花在哪里了?

  1. 通过普通二级索引树idx_create_time,过滤create_time条件,找到满足条件的记录ID。
  2. create_time是非聚簇索引,需要先查询出主键ID,再回表查询,通过主键ID查询出所有字段
  3. 扫描满足条件的100010行,然后扔掉前100000行,返回。

索引回表流程

在这里插入图片描述

优化方案

子查询优化

先用子查询查出符合条件的主键,再用主键ID做条件查出所有字段。

select * from tbl_user
where id in (
 select id from (
    select id from user 
    where create_time>'2022-07-03' 
    limit 100000,10
 ) as t
);

在这里插入图片描述

可以看到Extra列显示子查询中用到Using index,表示用到了覆盖索引,所以子查询无需回表查询,加快了查询效率。

使用分页游标

实现方式就是:当我们查询第二页的时候,把第一页的查询结果放到第二页的查询条件中。

例如:首先查询第一页

select * from tbl_user
where create_time>'2022-07-03' 
limit 10;

然后查询第二页,把第一页的查询结果放到第二页的查询条件中:

select * from tbl_user
where create_time>'2022-07-03' and id>10 
limit 10;

这样相当于每次都是查询第一页,也就不存在深分页的问题了,这种场景比较适合于没有调整到第XX页的场景上。例如APP页面滚动的场景上,互联网APP一般采用瀑布流的形式,比如百度首页、头条首页,都是一直向下滑动翻页,并没有跳转到制定页数的需求。

INNER JOIN 延迟关联

延迟关联的优化思路,跟子查询的优化思路其实是一样的:都是把条件转移到主键索引树,然后减少回表。不同点是,延迟关联使用了inner join代替子查询。

SELECT  user1 .id,user1 .name FROM tbl_user user1 INNER JOIN (SELECT a.id FROM tbl_user a WHERE a.update_time >= '2020-09-19' ORDER BY a.update_time LIMIT 100000, 10) AS  user2 on user2 .id= user2 .id;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值