分页查询的几种思路

论坛 期权论坛 脚本     
已经匿名di用户   2022-5-29 19:38   2110   0

背景:今天发现一个获取list的接口返回空的数据,一看日志发现是超时了,不由得就分析起来了原因,看了代码发现应该是怀疑两个地方有些问题,一个是获取数据的地方,一个是获取count的地方。

于是连上只读库测试查询语句,发现了count那里真的很慢,我用的是mongo,因为符合查询结果的条件就很多,所以count就很慢,索引也不能减少时间,奇怪了,难道mongo的count真的要一条条数吗。。。

查了下count为什么那么慢,也没有找到什么值得信服的理由,但有人建议,count另存,不要查询条件去count。好吧,这是一个优化点。然后我的分页用的是最简单的方法,下面开始说下常见的分页思路,注意前提是排除获取count的消耗,下面只说的是分页的思路。

一、 skip and limit

最简单的一种,不需要额外的处理,直接skip就完事了。当然缺点也很明显,当数据量比较大的时候,这里就会有性能问题,假如现在在1w页的地方,每页10条,我想到1w1页,此时从界面来看我只是简单的翻一页,但是db 查询要skip10w条,这个就可划不来了。而且这种每次都需要返回总count,便于显示多少页,比如count结果是10w条,每页10条,那么就有1w页。

二、gt lt 某个字段

伪代码就是db.find({id:{$gt:xxx}}).sort({id:1}).limit(pagesize)

前置条件:需要将每页的最后一个id返回给前端(往前翻的是要就要传每页的第一个id,并且使用lt, sort id : -1),然后翻页的时候前端传过来。当然你也可以指定别的字段,比如时间戳等

优点:显而易见,只需要在id上建索引,想去哪就去哪,性能没问题

缺点:1.需要保证你比较的那个字段唯一,不能有重复的,假如有多个重复的id,你使用gt id,就跳过了后面好多个相等id的内容,但是有人该说了,使用gte吧,那怕是可能永远也翻不过去页了。

2.不能跳到某页,只能一页页的翻,也不知道有多少页,除非你把count单独存。

三、双剑合璧

那么我们有没有一种方法既能跳页,显示总页数,也能不会有性能问题呢?还是有的,虽然并不是那么完美,正如标题所说,双剑合璧,即把上面两种方法的优点结合,组合成第三种

伪代码

var current_id int

N 当前页与要翻页页数的差的绝对值 ,page_size就是每页显示的条数

比如要从第三页到第五页,每页显示10条,N = 2,page_size=10, current_id就是第三页的第一个id

1.向前翻页 db.find({id:{$gte:current_id}}).skip(N*page_size).limit(page_size).sort({id:1})

同理第五页到第三页,每页显示10条,此时N=2, page_size=10,current_id就是第五页的第一个id

2.向后翻页 db.find({id:{$lt:current_id}}).skip((N-1)*page_size).limit(page_size).sort({id:-1})

缺点也明显,就是一下跳到最后一页,还是有点慢的,不过相邻页之间无压力

常用于下面的实现,参考链接https://stackoverflow.com/questions/9703319/mongodb-ranged-pagination

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP