MongoDB 分页查询的方法及性能

 

最近有点忙,本来有好多东西可以总结,Redis系列其实还应该有四、五、六…不过《Redis in Action》还没读完,等读完再来总结,不然太水,对不起读者。

自从上次Redis之后呢,算是对Nosql类型的产品有些入门了,这会换个方向,研究下真正的NoSql数据库——MongoDB。说起MongoDB,确实是用完了之后颠覆了我的数据管和程序观。怎么说呢?如果用在OO设计的程序里那真的太棒了,像我这种数据驱动、表驱动思想根深蒂固的人,思路很难一下子跟上MongoDB的节奏。当然并不是调用个api,写几句query那些思路,而是程序设计思路,业务领域的设计,如果OO,如何适合展现,适合查询,适合聚合运算等等。总之MongoDB重要的是程序的设计,设计好了,其实完全就忽略了Mongo的存储,因为mongodb实在是太方便了。

废话不多说,关于入门的资料、安装以及其他请拉到文章末尾,我附上了一些资料,以后如有必要再来分享。这篇文章着重的讲讲MongoDB的分页查询,为啥?分页可是常见的头号杀手,弄不好了,客户骂,经理骂。

传统的SQL分页

传统的sql分页,所有的方案几乎是绕不开row_number的,对于需要各种排序,复杂查询的场景,row_number就是杀手锏。另外,针对现在的web很流行的poll/push加载分页的方式,一般会利用时间戳来实现分页。 这两种分页可以说前者是通用的,连Linq生成的分页都是row_number,可想而知它多通用。后者是无论是性能和复杂程度都是最好的,因为只要简单的一个时间戳即可。

MongoDB分页

进入到Mongo的思路,分页其实并不难,那难得是什么?其实倒也没啥,看明白了也就那样,和SQL分页的思路是一致的。

先说明下这篇文章使用的用例,我在数据库里导入了如下的实体数据,其中cus_id、amount我生成为有序的数字,倒入的记录数是200w:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test
{
        /// <summary>
        /// 主键 ObjectId 是MongoDB自带的主键类型
        /// </summary>
        public ObjectId Id { get; set; }
        /// <summary>
        /// 客户编号
        /// </summary>
        [BsonElement("cust_id")]
        public string CustomerId { get; set; }
        /// <summary>
        /// 总数
        /// </summary>
        [BsonElement("amount")]
        public int Amount { get; set; }
        /// <summary>
        /// 状态
        /// </summary>
        [BsonElement("status")]
        public string Status { get; set; }
}

以下的操作基于MongoDB GUI 工具见参考资料3

首先来看看分页需要的参数以及结果,一般的分页需要的参数是:

  • PageIndex    当前页
  • PageSize      每页记录数
  • QueryParam[]  其他的查询字段