大家都写过分页查询,通过mysql的limit关键字,例如我要查第一页10条,那么就是Limit 0,10。这看起来没啥问题。假如数据量很大,页数很多,我查第100000页的10条,那就是Limit 100000,10。MySQL的limit⼯作原理就是先读取前⾯100000条记录,然后抛弃前100000条,读后⾯10条想要的,所以⻚码越⼤,偏移量越⼤,性能就越差。
解决MySQL深分页问题的方法有以下几种:
- 使用覆盖索引
覆盖索引能够同时满足查询条件和返回的列,这样就可以避免回表,从而提高查询性能。例如,如果查询条件是update_time > '2023-08-23 00:00:00',并且需要返回的列是id、name和update_time,那么可以使用update_time列作为覆盖索引。
- 使用游标
每次接⼝都会返回查询出来的数据的最⼤的id(游标),下⼀次查询传⼊这个游标,服务端只需要根据这个游标,取出id⼤于这个游标的n个数据即可。n为每⻚展示条数。(要知道上次查询的id,并且id自增)游标是一种可以从结果集逐行遍历的机制。使用游标可以避免一次性查询出所有数据,从而降低内存占用和I/O压力。这种方法在处理大数据量时可以获得更好的性能,但需要在应用程序中实现逻辑。
- 使用缓存
如果数据不经常变动,并且对实时性要求不高,可以考虑将结果集缓存在应用程序或缓存层中。这样,在需要获取深页数据时,可以从缓存中直接获取,避免了MySQL查询的开销。
- 改进业务逻辑
如果可以改进业务逻辑,避免深分页,那么也是解决深分页问题的一种方法。例如,可以将查询条件改为update_time >= '2023-08-23 00:00:00' AND update_time < '2023-08-24 00:00:00',这样就可以将查询范围缩小到一天内,从而避免深分页。
- 使用主键范围分页
如果使用的是自增主键,可以利用主键的顺序特性来进行分页。通过记录上一页的最后一条记录的主键值,使用LIMIT和WHERE子句以大于该主键值的条件查询下一页的结果。这样可以避免扫描和跳过大量记录的开销。
- 数据分片
如果数据量非常大且无法通过其他优化手段解决,可以考虑将数据进行分片存储。将数据按照某个规则或条件分散到多个表或数据库中,每个分片存储一部分数据。然后根据分页需求,只查询需要的分片,从而减少每次查询的数据量。
具体选择哪种方法,需要根据实际情况进行分析。




