优化LIMIT分页
在系统中需要进行分页才做的时候,我们通常会使用LIMIT加上偏移量的办法实现。
比如:
explain select * from orders limit 10 offset 10 ;
一个非常常见又令人头疼的问题就是,在偏移量非常大的时候(翻页到非常靠后的页面),例如可能是LIMIT 10000,10这样的查询,这时MySQL需要查询10020条记录然后只返回最后20条,前面10000条记录都被抛弃,这样的代价非常高。
那么如何优化这类查询呢?
第一步
首先对于这个查询select id from orders;
我们可以explain
一下
explain select id from orders;
会发现这是一个索引扫描(在存在辅助索引的情况下),相对表扫描这
个是会快很多的
第二步
基与上面的理论那么先将需要的id取出来 然后做一个子查询
select * from orders WHERE id >= (select id from orders order by id limit 1 offset 10000) limit 10;
不过这个查询是基于ID自增的假设,如果ID不是自增, 那么可以通过INNER JOIN
来改写
select * from orders INNER JOIN (select id from orders order by id LIMIT 10 offset 10000) t USING (id);
补充
-
分页的显示
- 如果有获取数据总数 那么通过总数自然可以得到页数
一般获取数据总数是一个索引扫描,如果数据量很大在innodb下对于sql什么优化的有段 - 如果没有总数 那么获取的时候多获取一些数据, 比如每页20个 我获取21个 如果能取到自然有下一页
- 如果有获取数据总数 那么通过总数自然可以得到页数
-
还是很慢怎么解决
- 从业务考虑 是否真的需要这种翻页, 因为普通用户的话很少会关心历史数据
- 可以考虑按时间段分表
- 维护一根分页表,这样直接就可以获得某也有多少数据
- 交给其他工具去做,不让mysql做自己不擅长的事情
总结
优化此类分页查询的一个最简单的办法就是尽可能地使用索引覆盖查询,而不是查询所有的列。然后根据需要做一个关联操作再返回所需的列。对于偏移量很大的时候,这样做的效率会提升很大。