话不多说,直接从案例说明
案例一:覆盖索引+子查询优化
-- 分页查询用户信息,其中update_date为普通索引
select id, name, age from t_user where update_date > '2023-07-01' limit 1000000,10;
为什么慢?
在走update_date索引的前提下,该SQL执行流程:
- 走update_date索引查询符合条件的1000010条数据,这里只能获取到id;
- 走聚簇索引(回表)获取id,name,age字段;
- 返回1000010条数据到server层,根据offset的值挨个抛弃,然后只获取第1000001~1000010这10条数据
总结:
- 分页的深度越深,需要获取到server层的数据量就更多,只拿到符合条件的10条,但是需要获取100w零10条数据
如何优化?
先看优化后的SQL:
-- 覆盖索引+子查询优化
select id, name, age from t_user
where id >= (
select u.id from t_user u
where u.update_date > '2023-07-01'
limit 1000000,1
)
limit 0, 10;
优化后SQL的执行看流程:
- 走update_date索引查询符合条件的1000010条数据,这里只能获取到id;
- 返回这1000010个id到server层进行过滤,获取到最终的1个id;
- 走主键索引获取10条数据,这里有完整的数据(包括id, name, age)
总结:
- 其实区别在于返回server层过程中,只会拷贝行内的id这一列的数据,不会拷贝整行数据,在数据量大的时候,这部分耗时也是非常明显的;
- 少了大数据回表的步骤,优化后只需要根据id查询size的数据返回即可
案例二:游标方式优化
-- 案例
select id, name, age from t_user order by id desc limit 1000000,10;
-- 游标方式优化后
select id, name, age from t_user where id >= 1000000 order by id desc limit 10;
这里的执行流程就不说了,总结:
- offset偏移量可以由前端传给后端,后端以防万一做数据合法性校验如offset最大值控制即可