一种深度分页优化查询效率的实现方法

前提:

此方法只适用于排好序的数据顺序不会变,只会往后面继续排的情况,比如记录表(不存在删除的情况)且按创建时间排序(正序倒序都可)。

当数据量特别大的时候如几千万的时候,通过普通的limit,offset分页去查询最后一页时会耗费大量的时间,我们的主要思路就是去掉offset来实现快速查询。

去掉offset 第一个想到的就是通过游标的方式,将第一页最后一条排序字段传回去,查询第二页的时候带上,这样可以通过where条件来避免offset,每页的查询效率是相同的。

但是上面这个方法存在一个问题,我们无法实现跳页查询,比如我无法实现第一页直接跳到最后一页。这个时候可以考虑将数据打点,比如每1000条存一个游标在redis,使用redis的map,key取当前条数,值取游标(map为了快速查询),然后再将map的key存一份在redis的list里面(list为了排序)这里刷新数据可以通过定时任务,或者集成再业务里面,比较灵活。

redis中数据如下图

一种深度分页优化查询效率的实现方法_第1张图片

 一种深度分页优化查询效率的实现方法_第2张图片

查询时 比如要查询第3568-3578条,这个时候只需要往前找一个的游标 3001,通过3001的游标可以直接查询3002-3578条即可,然后通过代码卡最后十条就可以了。

这里需要注意3001本身是无法查询到的,如果你刚好查询 3001-3011条数据这时候你应该使用2001作为游标 查询2002-3011这些数据。

可能存在的问题

1.我页面需要创建时间最近的显示在第一页

这个问题其实不影响我们索引的创建,创建游标的时候依旧是老的数据在前,新的在后。查询的时候不管页面展示正序或者倒序,我们先明确我们要查询的数据是正序的多少到多少条,然后就可以卡好数据,倒序无非是需要多一个查询总数和最后结果集反转的过程。

2.我使用创建时间排序,但是创建时间有重复的

这个问题我们就需要多字段排序了,比如用 创建时间升序之后再用id升序,这时候卡游标就不能简单的用两个字段都大于了,而是需要下面这种:

select * from table where create_time>='2023-05-28 12:19:13'and not (create_time='2023-05-28 12:19:13' and id <='9bc48ca0-ff90-11ed-b12f-3636c5ed1aa8') ORDER BY create_time asc, id asc limit 10 ;

索引方面则需要给游标字段创建索引:

CREATE INDEX idx_create_time_id ON table (create_time asc, id asc);

不过这个办法的应用场景应该并不多,且没有办法使用条件,可能还需要写两个分支进行查询,所以很鸡肋,仅作记录。

你可能感兴趣的:(sql,数据库,java,mysql,sql,redis)