序
当数据库数量超过百万级时,分页尾页查询的性能会降低,因为分页的逻辑是查出offset+size的数据,然后丢弃offset的数据,这就导致页码较大时近乎全表查询。
例
我的测试表中有近100W条数据,自增主键,当我想查询最后的分页时,耗费的时间是1秒以上。
方案一:子查询
当SQL 语句通过索引能直接获取结果,那就不需要回表查询,这时效率会大大提升,这种方式为覆盖索引查询。
由此我们可以先查询分页后最小的主键ID,然后再根据ID的条件来取数据
SELECT `id` FROM `t_test` LIMIT 949340,1; -- 949342
SELECT * FROM `t_test` WHERE `id` >= (SELECT `id` FROM `t_test` LIMIT 949340,1) LIMIT 10; -- 0.68秒
虽然效率提升了不少,但好像有诸多限制。没错,使用此种方式来优化分页的话是有很多限制,如下:
- 主键必须连续。一般使用自增主键或雪花ID的话是可以保证连续的。
- 排序的字段顺序必须和主键顺序一致。如果不一致会丢失正确数据。
- 无法添加其他条件查询。
方案二:JOIN查询
方案一有诸多限制,我们可以使用JOIN方式来改写SQL,如下:
SELECT * FROM `t_test` a JOIN (SELECT `id` FROM `t_test` LIMIT 949340,10) b ON a.id=b.id; -- 0.69秒
此种方式是先根据过滤条件获取主键ID,然后在和本表做关联取所有数据。推荐使用这种方式,因为其解决了方案一的所有限制并且效率也可以。