关于mongodb的分页问题
发布于 10 年前 作者 xyc-cn 5962 次浏览 最后一次编辑是 8 年前 来自 问答

好多人说mongodb分页不要用skip,但是网上搜了好久也没搜到解决办法 以前学过java,他们基于Mysql数据库的分页好像是取得符合查询的全部数据放在list里面 然后fetch带两个参数去取数据,实现分页 我就想着能不能也使用这个办法,然后自己写了个简单的实现类 代码在http://blog.csdn.net/chengscau/article/details/40188087 求大家告诉我好点的解决方案,有代码看是最好了~

14 回复

先缩小范围,然后再分页。 你用sql也是一样。

卧槽。。。你这个方法是把所有可能的数据都取到服务端来,然后在服务端实现分页。这样的效率绝逼比 mongodb 做 skip 要低得多啊。

不是一次性读取所有的数据,应该是:

  • 确定分页依据的记录域(field),建立索引;
  • 每次执行一个区间查询(range query),对这次查询结果分页。注意:要根据上一次区间查询的结果,修改本次区间查询的条件。

参考代码:MongoDB数据库,使用区间查询分页

MongoDB cursor.skip文档也是推荐使用区间查询,实现高效地分页。

还可以参考这个演示文稿(可能需要科学上网):应该这么分页,内容是使用PostgresSQL数据库,利用区间查询而不是SQL OFFSET实现分页功能,比较了两种方法的查询性能。

@alsotang 新人不懂事,谢谢指点- -

@bnuhero 虽然还是迷迷糊糊的,但是谢谢指点了,我再好好看看~!

@tulayang 确定大致的分页区间是吧

@xyc-cn

比如你的数据全部有1千条, 跳过900条,返回10条,你要扫描910条数据。

先用大于小于或者其他的匹配,缩小到第900条,然后返回10条,那么扫描的条数可能只有几十个。

@tulayang 用大于或者小于,这样比如在第一页,我要跳到第二页,我可以传第一页最后个数据的id过去后台,然后后台通过这个id去缩小范围

@tulayang 但是如果我当前在第一页,但是我想跳到第十页,我该怎么操作,还是利用第一页最后的的id去缩小范围,然后分割下获取到的数组数据么

@xyc-cn

有两种处理方法:

  1. 不用页面底部显示<< < 1 2 3 4 5 > >>的方式,而是采用twitter或者微博那种无限下拉获取新记录的方式。这实际上相当于每次只能读取下一页的内容,也就不存在用户跳到特定页面的问题;

  2. 仍然采用页面底部显示<< < 1 2 3 4 5 > >>的方式,是不是可以一次读取5页的内容?在这5页范围内的跳转,就不用再读数据库。如果要调到第6页,那就再来一次区间查询。

@bnuhero 恩,我也是大概这样想,然后我还有个问题,取得第一页数据的时候,怎么确定起始区间,难道去数据库看么?还有指定 区间是不是起始和结束位置都要指定,还是只是指定一个起始查询的位置

查询比较耗时的操作也可以考虑缓存起来啊,改数据结构多麻烦。

目前我个人所知的分页方式有两种: 1)skip + limit 的方式 2)$gt($get) + $lt($lte) + limit 的方式

第一种方式更适合pc网页的数字分页 屏幕快照 2014-10-19 07.56.50.png 第二种方式更适合mobile网页的上一页和下一页的分页 屏幕快照 2014-10-19 07.54.56.png

关于性能问题, 能确定的是:尽量配合一个能大幅度缩小mongodb查询范围的查询条件 举个例子: 如果 topic 列表按照最后更新时间字段 last_update_date 倒序排列, 除了limit和确保击中索引 { last_update_date:-1 } 之外, 实际查询条件可以加入一天的查询: { last_update_date:{$gte:new Date(‘2015-01-01 00:00:00’), $lte:new Date(‘2015-01-02 23:59:59’)}}

这种方式在能有效控制mongodb查询数据的时间成本。

回到顶部