问题:在业务中,分页查询的场景非常多见,比如脚本分批处理数据;比如页面上需要分页查看列表。
假设是按照自增主键排序后分页,最开始的时候肯定没问题:
SELECT * from table_name order by id desc limit 0,20;
OK, Time: 0.007000s
但是如果翻到后面,情况肯定就不好了...
SELECT * from table_name order by id desc limit 10000000,20; OK, Time: 15.588000s
具体耗时根据表的大小和数据库服务器而不同,是否能接受也看业务的具体情况,下面我们看下这种情况是为什么,以及如何优化。
explain一下慢查询语句,可以看到:
显然rows就是查询慢的罪魁祸首了,Handler_read_prev 10000019 Number of requests to read the previous row in key order. Mainly used to optimize ORDER BY ... DESC.
这里要注意,即使在有索引的情况下,limit...offset操作也会从头扫数据。
接下来是解决方案:
利用索引覆盖,可以省去回表的耗时。
SELECT * from table_name order by id desc limit 10000000,1; OK, Time: 17.751000s
SELECT id from table_name order by id desc limit 10000000,1;
OK, Time: 5.370000s
所以改成如下SQL一般会快一些:
SELECT * from table_name where id >= (SELECT id from t_movie_schedule order by id desc limit 10000000, 1) limit 1; OK, Time: 6.912000s
但是很迷的是上面这个SQL不太稳定,似乎没有分开执行这两个SQL快
SELECT id from table_name order by id desc limit 10000000, 1; SELECT * from table_name where id >= (635883593) limit 1;
先忽略掉上面这个问题,也可以考虑在代码里去处理这个问题,分两步来查询。
至于为什么select id会更快,我们需要了解下聚簇索引和回表的概念,这篇博客讲得很清楚:https://www.cnblogs.com/boluopabo/p/12869348.html