一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

用C#封装的Mongodb底层通用类分享

时间:2015-08-09 编辑:简简单单 来源:一聚教程网

这里主要是讲我封装的底层,不涉及到Mongodb的安装,启动,可视化查询等东西,后面会附上一些参考的地址供大家一起学习。

目前mongodb提供的驱动主要有两种:

1.官网驱动  下载地址:http://github.com/mongodb/mongo-csharp-driver/downloads
2.第三方的samus驱动 下载地址:https://github.com/samus/mongodb-csharp

两个驱动的运用自己都有使用过,个人感觉官方的驱动提供的方法比较多,用起来也比较顺手,而且更新度比samus的高,所以自己使用的是官方的驱动。

官网驱动的简单使用

主要使用下面的两个dll

MongoDB.dll          驱动的主要程序
MongoDB.GridFS.dll    用于存储大文件。

基本的增删改查代码如下:

//数据库连接字符串
const string strconn = "mongodb://127.0.0.1:27017";
//数据库名称
const string dbName = "cnblogs";
//定义数据库
MongoDatabase db;
/// 
/// 打开数据库链接
/// 
public void GetConnection()
{
//定义Mongo服务
 Mongo mongo = new Mongo(strconn);
//打开连接
 mongo.Connect();
//获得数据库cnblogs,若不存在则自动创建
 db = mongo.GetDatabase(dbName) as MongoDatabase;
}
/// 
/// 添加数据
/// 
public void Insert()
{
var col = db.GetCollection();
//或者 
//var col = db.GetCollection("Users");
Users users = new Users();
users.Name = "xumingxiang";
users.Sex = "man";
col.Insert(users);
}
/// 
/// 更新数据
/// 
public void Update()
{
var col = db.GetCollection();
//查出Name值为xumingxiang的第一条记录
 Users users = col.FindOne(x => x.Name == "xumingxiang");
//或者 
//Users users = col.FindOne(new Document { { "Name", "xumingxiang" } });
 users.Sex = "women";
col.Update(users, x => x.Sex == "man");
}
/// 
/// 删除数据
/// 
public void Delete()
{
var col = db.GetCollection();
col.Remove(x => x.Sex == "man");
////或者
////查出Name值为xumingxiang的第一条记录
 //Users users = col.FindOne(x => x.Sex == "man");
//col.Remove(users);
}
/// 
/// 查询数据
/// 
public void Query()
{
var col = db.GetCollection();
var query = new Document { { "Name", "xumingxiang" } };
//查询指定查询条件的全部数据
 var result1 = col.Find(query);
//查询指定查询条件的第一条数据
 var result2 = col.FindOne(query);
//查询全部集合里的数据
 var result3 = col.FindAll();
}



封装扩展使用

1.数据库配置文件

考虑到一个项目里面可能使用到不同的数据库(比如:普通数据和文件数据等分别存到不同数据库中),也有可能会跨服务器查询,所以这里首先创建一个配置文件帮助类,主要是可以进行多个数据库配置,满足跨服务器,跨数据的需求。

配置格式如下:



  
    
    
    
  


Xml序列化对象类   

public class ServiceConfig
{
    [XmlArray, XmlArrayItem("Item")]
    public List mongodbs { get; set; }
}
[XmlRoot]
public class mongodbConfig
{
    [XmlAttribute("dbName")]
    public string dbName { get; set; }
    [XmlAttribute("hostName")]
    public string hostName { get; set; }
}


读取配置文件管理类

public class ManagerConfig
{
    public static string ConfigPath;
    //加载配置文件
    static ManagerConfig()
    {
        ConfigPath = "./config.xml";
    }
    //xml序列化后的对象
    private static ServiceConfig _settings;
    public static ServiceConfig ServiceSettings
    {
        get
        {
            return _settings ?? (_settings = Load());
        }
    }
    //加载xml序列化为ServiceConfig对象
    static ServiceConfig Load()
    {
        if (File.Exists(ConfigPath))
        {
            using (FileStream fs = new FileStream(ConfigPath, FileMode.Open))
            {
                XmlSerializer xs = new XmlSerializer(typeof(ServiceConfig));
                //序列化为一个对象
                _settings = (ServiceConfig)xs.Deserialize(fs);
            }
        }
        else
        {
            throw new Exception("数据库配置文件不存在,请检查");
            //_settings = new ServiceConfig();
        }
        return _settings;
    }
}


2.实体通用接口

mongodb中本身没有自增ID的属性,自带有一个ObjectID,为了统一每个实体对象都有这个ID ,这里建立一个通用接口和一个底层实体基类来进行规范化处理

实体接口   

public interface IMongoEntity
{
    string Id { get; }
}


底层实体基类   

public class BaseModel : IMongoEntity
{
    [BsonIgnore]
    public string Id
    {
        get
        {
            if (_id == ObjectId.Empty)
                _id = ObjectId.GenerateNewId(DateTime.Now);
            return _id.ToString();
        }
    }
    [BsonId]
    private ObjectId _id;
}


实体类的例子(继承于BaseModel类) 

public class UserEntity : BaseModel
{
    public string UserName { get; set; }
    public int Num { get; set; }
    //MongoDB中存储的时间是标准时间UTC +0:00  (相差了8个小时)
    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
    public DateTime PostTime { get; set; }
}


3.Mongodb通用帮助基类 (主要类)

public class MongodbBase where T : class,IMongoEntity
{
    protected MongoServer server = null;
    protected MongoDatabase db = null;
    protected MongoCollection collection;
    protected void Init(string DbName)
    {
        var Item = ManagerConfig.ServiceSettings.mongodbs.Where(p => p.dbName == DbName).FirstOrDefault();
        if (Item == null)
        {
            throw new Exception("不存在数据库为: " + DbName + " 的配置对象,请检查");
        }
        else
        {
            server = MongoDB.Driver.MongoServer.Create(Item.hostName);
            db = server.GetDatabase(Item.dbName);
            collection = db.GetCollection(typeof(T).Name.Replace("Entity", ""));
        }
    }
    #region 查询
    /// 
    /// 根据ID获取对象
    /// 
    /// 
    /// 
    public T GetModelById(string id)
    {
        return collection.FindOneById(id);
    }
    /// 
    /// 获取一条记录(自定义条件)
    /// 
    /// 
    public T FirstOrDefault(Expression> expression)
    {
        MongoDB.Driver.IMongoQuery query = Query.Where(expression);
        return collection.FindOne(query);
    }
    /// 
    /// 获取一条记录
    /// 
    /// 
    public T FirstOrDefault()
    {
        return collection.FindAll().FirstOrDefault();
    }
    /// 
    /// 获取全部
    /// 
    /// 
    public List FindAll()
    {
        return collection.FindAll().ToList();
    }
    /// 
    /// 获取全部(自定义条件)
    /// 
    /// 
    public List FindAll(Expression> expression)
    {
        MongoDB.Driver.IMongoQuery query = Query.Where(expression);
        return collection.Find(query).ToList();
    }
    /// 
    /// 根据条件获取数量
    /// 
    /// 
    /// 
    public long GetCount(Expression> expression = null)
    {
        if (expression == null)
        {
            return collection.Count();
        }
        else
        {
            return collection.Count(Query.Where(expression));
        }
    }
    /// 
    /// 根据ID判断是否存在
    /// 
    /// 
    /// 
    public bool Exists(string id)
    {
        return collection.FindOneById(id) != null;
    }
    /// 
    /// 分页
    /// 
    /// 总页码
    /// 页容量
    /// 总记录数
    /// 条件
    /// 是否是正序
    /// 排序的字段
    /// 
    public List Page(int PageIndex, int PageSize, out  long RowCounts, Expression> expression = null, bool IsAsc = true, params string[] OrderFiled)
    {
        MongoCursor mongoCursor;
        //条件选择
        if (expression != null)
        {
            RowCounts = collection.Find(Query.Where(expression)).Count();
            mongoCursor = collection.Find(Query.Where(expression));
        }
        else
        {
            RowCounts = collection.FindAll().Count();
            mongoCursor = collection.FindAll();
        }
        //排序
        if (OrderFiled != null && OrderFiled.Length > 0)
        {
            //处理主键字段
            for (int i = 0; i < OrderFiled.Length; i++)
            {
                if (OrderFiled[i].Equals("id", StringComparison.CurrentCultureIgnoreCase))
                {
                    OrderFiled[i] = "_id";
                }
            }
            if (IsAsc)
            {
                mongoCursor = mongoCursor.SetSortOrder(SortBy.Ascending(OrderFiled));
            }
            else
            {
                mongoCursor = mongoCursor.SetSortOrder(SortBy.Descending(OrderFiled));
            }
        }
        return mongoCursor.SetSkip((PageIndex - 1) * PageSize).SetLimit(PageSize).ToList();
    }
    #region 效率低,暂时不用
    ///// 
    ///// 分页
    ///// 
    ///// 
    //public List Page(int PageIndex, int PageSize, out  long RowCounts, Expression> expression = null)
    //{
    //    List ret = new List();
    //    IQueryable queryable;
    //    //条件选择
    //    if (expression != null)
    //    {
    //        queryable = collection.Find(Query.Where(expression)).AsQueryable();
    //    }
    //    else
    //    {
    //        queryable = collection.FindAll().AsQueryable();
    //    }
    //    RowCounts = queryable.Count();
    //    ret = queryable.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList();
    //    return ret;
    //}
    ///// 
    ///// 分页
    ///// 
    ///// 
    ///// 
    ///// 
    ///// 
    ///// 
    ///// 
    ///// 
    ///// 
    //public List Page(int PageIndex, int PageSize, out  long RowCounts, Expression> expression = null, Expression> orderBy = null, bool IsOrder = true)
    //{
    //    List ret = new List();
    //    IQueryable queryable;
    //    //条件选择
    //    if (expression != null)
    //    {
    //        queryable = collection.Find(Query.Where(expression)).AsQueryable();
    //    }
    //    else
    //    {
    //        queryable = collection.FindAll().AsQueryable();
    //    }
    //    //排序
    //    if (orderBy != null)
    //    {
    //        if (IsOrder)
    //        {
    //            queryable = queryable.OrderBy(orderBy);
    //        }
    //        else
    //        {
    //            queryable = queryable.OrderByDescending(orderBy);
    //        }
    //    }
    //    RowCounts = queryable.Count();
    //    ret = queryable.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList();
    //    return ret;
    //} 
    #endregion
    #endregion
    #region 删除
    /// 
    /// 带条件的删除
    /// 
    /// 
    /// 
    public void Delete(Expression> expression)
    {
        MongoDB.Driver.IMongoQuery query = Query.Where(expression);
        var result = collection.Remove(query);
    }
    /// 
    /// 根据模型删除
    /// 
    /// 
    public void Delete(T model)
    {
        MongoDB.Driver.IMongoQuery query = Query.Where(p => p.Id == model.Id);
        collection.Remove(query);
    }
    /// 
    /// 根据ID删除
    /// 
    /// 
    public void Delete(string Id)
    {
        MongoDB.Driver.IMongoQuery query = Query.Where(p => p.Id == Id);
        collection.Remove(query);
    }
    /// 
    /// 全部删除
    /// 
    /// 
    public void DeleteAll()
    {
        var result = collection.RemoveAll();
    }
    #endregion
    #region 添加
    /// 
    /// 单模型添加
    /// 
    /// 
    /// 
    public void Insert(T model)
    {
        var result = collection.Insert(model);
    }
    /// 
    /// 批量添加
    /// 
    /// 
    /// 
    public void InsertBatch(List model)
    {
        collection.InsertBatch(model);
    }
    #endregion
    #region 修改
    /// 
    /// 修改
    /// 
    /// 
    /// 
    public void Update(T model)
    {
        var result = collection.Save(model);
    }
    /// 
    /// 批量修改
    /// 
    /// 
    public void UpdateAll(List model)
    {
        model.ForEach(e => collection.Save(e));
    }
    #endregion
}


4.业务类

当新建一个表(mongodb里面叫做集合),需要对其进行操作,包括一些业务处理时。首先继承MongodbBase类,然后使用Init方法初始化对象,如下面的UserServcices类

public class UserServices : MongodbBase
{
    public UserServices()
    {
        this.Init("myDb");
    }
}



5.使用    

[TestClass]
public class UnitTest1
{
    Random rd = new Random();
    UserServices ubll = new UserServices();
    #region 添加
    [TestMethod]
    public void 添加()
    {
        UserEntity model = new UserEntity();
        model.UserName = "Name" + rd.Next(100, 10000);
        model.Num = rd.Next(100, 10000);
        model.PostTime = DateTime.Now;
        ubll.Insert(model);
    }
    [TestMethod]
    public void 添加复杂模型()
    {
        ComplexEntity model = new ComplexEntity();
        ComplexServices cbll = new ComplexServices();
        model.Name = "Complex";
        model.Schools = new List();
        model.Schools.Add(new School()
        {
            Master = new Grade()
            {
                Name = "Master"
            },
            Name = "School",
            Students = new List()
        });
        model.Schools[0].Students.Add(new Student() { Age = 22, Name = "张三" });
        cbll.Insert(model);
    }
    [TestMethod]
    public void 批量添加()
    {
        List Data = new List();
        for (int i = 0; i < 1000000; i++)
        {
            UserEntity model = new UserEntity();
            model.UserName = "Name" + rd.Next(100, 10000);
            model.Num = rd.Next(100, 10000);
            model.PostTime = DateTime.Now;
            Data.Add(model);
        }
        ubll.InsertBatch(Data);
    }
    #endregion
    #region 修改
    [TestMethod]
    public void 获取单个对象_修改()
    {
        var model = ubll.FirstOrDefault(p => p.Id != "");
        model.UserName = "new1";
        ubll.Update(model);
    }
    [TestMethod]
    public void 批量修改()
    {
        var model = ubll.FindAll();
        for (int i = 0; i < model.Count; i++)
        {
            model[i].UserName = "Text";
        }
        ubll.UpdateAll(model);
    }
    #endregion
    #region 查询
    [TestMethod]
    public void 获取全部对象()
    {
        var model = ubll.FindAll();
        var count = model.Count;
    }
    [TestMethod]
    public void 获取单个对象()
    {
        var model = ubll.FirstOrDefault();
        var count = model.PostTime;
    }
    [TestMethod]
    public void 根据ID获取对象()
    {
        var model = ubll.GetModelById("eeef22d6-7ac6-40cd-9312-59ab15fd904a");
    }
    [TestMethod]
    public void 获取全部对条件象_带条件()
    {
        var model = ubll.FindAll(p => p.UserName.Contains("Name"));
        var count = model.Count;
    }
    [TestMethod]
    public void 分页()
    {
        long Rows;
        List pageDate = new List();
        pageDate = ubll.Page(300, 20, out Rows, p => p.Num > 1500);
        pageDate = ubll.Page(1, 20, out Rows, null, true, "Id");
        pageDate = ubll.Page(1, 20, out Rows, null, true, "Num");
        pageDate = ubll.Page(1, 20, out Rows, p => p.Num > 1500, false, "Id");
    }
    [TestMethod]
    public void 获取数量()
    {
        //不带条件
        var count = ubll.GetCount();
        //带条件
        var count1 = ubll.GetCount(p => p.Num > 5000);
    }
    #endregion
    #region 删除
    [TestMethod]
    public void 删除_自定义条件()
    {
        ubll.Delete(p => p.Num >= 2000);
    }
    [TestMethod]
    public void 删除_删除模型()
    {
        var model = ubll.FirstOrDefault();
        if (model != null)
        {
            ubll.Delete(model);
        }
    }
    [TestMethod]
    public void 删除_根据ID删除()
    {
        ubll.Delete("ec45ea8b-a551-46eb-ad58-1b4f5f2aab25");
    }
    [TestMethod]
    public void 删除_删除全部()
    {
        ubll.DeleteAll();
    }
    #endregion
    #region 其他
    [TestMethod]
    public void 同时创建两个对象_同一数据库内()
    {
        LogServices Logbll = new LogServices();
        UserEntity model = new UserEntity();
        model.UserName = "Name" + rd.Next(100, 10000);
        model.Num = rd.Next(100, 10000);
        model.PostTime = DateTime.Now;
        ubll.Insert(model);
        LogEntity log = new LogEntity();
        log.UserName1 = "Name" + rd.Next(100, 10000);
        log.Num1 = rd.Next(100, 10000);
        log.PostTime1 = DateTime.Now;
        Logbll.Insert(log);
        model.UserName = "Name" + rd.Next(100, 10000);
        model.Num = rd.Next(100, 10000);
        model.PostTime = DateTime.Now;
        ubll.Insert(model);
    }
    [TestMethod]
    public void 同时创建两个对象_不同一数据库内()
    {
        Log1Services Logbll = new Log1Services();
        UserEntity model = new UserEntity();
        model.UserName = "Name" + rd.Next(100, 10000);
        model.Num = rd.Next(100, 10000);
        model.PostTime = DateTime.Now;
        ubll.Insert(model);
        LogEntity log = new LogEntity();
        log.UserName1 = "Name" + rd.Next(100, 10000);
        log.Num1 = rd.Next(100, 10000);
        log.PostTime1 = DateTime.Now;
        Logbll.Insert(log);
        model.UserName = "Name" + rd.Next(100, 10000);
        model.Num = rd.Next(100, 10000);
        model.PostTime = DateTime.Now;
        ubll.Insert(model);
    }
    [TestMethod]
    public void 当指定名称不存在时候()
    {
        ErrorServices error = new ErrorServices();
    }
    #endregion
}


以上就是自己封装的整体逻辑和代码,不过这里面还有一些不明白和不足的地方,这里提出来,希望大神们帮我解答下:

1.返回值问题

在添,删,改的使用,根据官网提供的驱动,都有一个WriteConcernResult对象返回,可是在测试中发现,这个返回的对象永远都是null


2.增加ID问题

mongodb中本身没有自增ID的属性,自带有一个ObjectID,如果我需要一个自增ID,是否是自己建一个ID属性,然后在增加的时候自己控制+1?不过这样是否性能上比较低,还要考虑多线程并发的情况下加锁的问题。所以不知道这块大家是怎么去实现的?

3.分页效率的问题

一开始分页我是先将结果转为Queryable,然后在进行操作,这个代码里面有这段,暂时注释掉了,后面再博客园上看到了一个前辈的mongodb分析后,改了下分页的方式,测试过很快,但在带条件获取记录行总数的时候,发现测试300W数据下,获取总数需要600ms的时间,不知道是我方法用错了还是有其他更好的?




MongoDB 分页查询的方法及性能

这篇文章着重的讲讲MongoDB的分页查询,为啥?分页可是常见的头号杀手,弄不好了,客户骂,经理骂。

传统的SQL分页

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

MongoDB分页

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

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

public class Test
{
        /// 
        /// 主键 ObjectId 是MongoDB自带的主键类型
        /// 
        public ObjectId Id { get; set; }
        /// 
        /// 客户编号
        /// 
        [BsonElement("cust_id")]
        public string CustomerId { get; set; }
        /// 
        /// 总数
        /// 
        [BsonElement("amount")]
        public int Amount { get; set; }
        /// 
        /// 状态
        /// 
        [BsonElement("status")]
        public string Status { get; set; }
}


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

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

所以按照row_number的分页思想,也就是说取第(pageIndex*pageSize)到第(pageIndex*pageSize + pageSize),我们用Linq表达就是:

query.Where(xxx...xxx).Skip(pageIndex*pageSize).Take(pageSize)

查找了资料,还真有skip函数,而且还有Limit函数 见参考资料1、2,于是轻易地实现了这样的分页查询:

db.test.find({xxx...xxx}).sort({"amount":1}).skip(10).limit(10)//这里忽略掉查询语句

相当的高效,几乎是几毫秒就出来了结果,果然是NoSql效率一流。但是慢,我这里使用的数据只是10条而已,并没有很多数据。我把数据加到100000,效率大概是20ms。如果这么简单就研究结束了的话,那真的是太辜负了程序猿要钻研的精神了。sql分页的方案,方案可是能有一大把,效率也是不一的,那Mongo难道就这一种,答案显然不是这样的。另外是否效率上,性能上会有问题呢?Redis篇里,就吃过这样的亏,乱用Keys。

在查看了一些资料之后,发现所有的资料都是这样说的:
不要轻易使用Skip来做查询,否则数据量大了就会导致性能急剧下降,这是因为Skip是一条一条的数过来的,多了自然就慢了。

这么说Skip就要避免使用了,那么如何避免呢?首先来回顾SQL分页的后一种时间戳分页方案,这种利用字段的有序性质,利用查询来取数据的方式,可以直接避免掉了大量的数数。也就是说,如果能附带上这样的条件那查询效率就会提高,事实上是这样的么?我们来验证一下:

这里我们假设查询第100001条数据,这条数据的Amount值是:2399927,我们来写两条语句分别如下:

db.test.sort({"amount":1}).skip(100000).limit(10)  //183ms

db.test.find({amount:{$gt:2399927}}).sort({"amount":1}).limit(10)  //53ms

 
结果已经附带到注释了,很明显后者的性能是前者的三分之一,差距是非常大的。也印证了Skip效率差的理论。

C#实现

上面已经谈过了MongoDB分页的语句和效率,那么我们来实现C#驱动版本。
本篇文章里使用的是官方的BSON驱动,详见参考资料4。Mongo驱动附带了另种方式一种是类似ADO.NET的原生query,一种是Linq,这里我们两种都实现

方案一:条件查询 原生Query实现

var query = Query.GT(item => item.Amount, 2399927);                
var result = collection.Find(query).SetLimit(100)
                       .SetSortOrder(SortBy.Ascending("amount")).ToList();              
Console.WriteLine(result.First().ToJson());//BSON自带的ToJson

方案二:Skip原生Query实现

var result = collection.FindAll().SetSkip(100000).SetLimit(100)
             .SetSortOrder(SortBy.Ascending("amount"));
Console.WriteLine(result.ToList().First().ToJson());

方案三:Linq 条件查询

var result = collection.AsQueryable().OrderBy(item => item.Amount)
         .Where(item => item.Amount > 2399927).Take(100);
Console.WriteLine(result.First().ToJson());

方案四:Linq Skip版本

 var result = collection.AsQueryable().OrderBy(item => item.Amount).Skip(100000).Take(100);
Console.WriteLine(result.First().ToJson());

性能比较参考

这里的测试代码稍后我上传一下,具体的实现是利用了老赵(我的偶像啊~)的CodeTimer来计算性能。另外我跑代码都是用TestDriven插件来跑的。


方案一:

pagination GT-Limit
{ "_id" : ObjectId("5472e383fc46de17c45d4682"), "cust_id" : "A12399997", "amount" : 2399928, "status" : "B" }
Time Elapsed:    1,322ms
CPU Cycles:    4,442,427,252
Gen 0:         0
Gen 1:         0
Gen 2:         0



方案二:

pagination Skip-limit
{ "_id" : ObjectId("5472e383fc46de17c45d4682"), "cust_id" : "A12399997", "amount" : 2399928, "status" : "B" }
Time Elapsed:    95ms
CPU Cycles:    18,280,728
Gen 0:         0
Gen 1:         0
Gen 2:         0



方案三:

paginatiLinq on Linq where
{ "_id" : ObjectId("5472e383fc46de17c45d4682"), "cust_id" : "A12399997", "amount" : 2399928, "status" : "B" }
Time Elapsed: 76ms
CPU Cycles: 268,734,988
Gen 0: 0
Gen 1: 0
Gen 2: 0



方案四:

pagination Linq Skip
{ "_id" : ObjectId("5472e383fc46de17c45d4682"), "cust_id" : "A12399997", "amount" : 2399928, "status" : "B" }
Time Elapsed:    97ms
CPU Cycles:    30,834,648
Gen 0:         0
Gen 1:         0
Gen 2:         0


上面结果是不是大跌眼镜,这和理论实在相差太大,第一次为什么和后面的差距如此大?刚开始我以为是C# Mongo的驱动问题,尝试了换驱动也差不多。这几天我在看《MongoDB in Action》的时候,发现文章里提到:
MongoDB会根据查询,来加载文档的索引和元数据到内存里,并且建议文档元数据的大小始终要保持小于机器内存,否则性能会下降。

注意到了上面的理论之后,我替换了我的测试方案,第一次执行排除下,然后再比较,发现确实结果正常了。

方案一的修正结果:

pagination GT-Limit
{ "_id" : ObjectId("5472e383fc46de17c45d4682"), "cust_id" : "A12399997", "amount
" : 2399928, "status" : "B" }
Time Elapsed:   18ms
CPU Cycles:     54,753,796
Gen 0:          0
Gen 1:          0
Gen 2:          0



总结

这篇文章,基于Skip分页和有序字段查询分页两种方案进行的对比。后者说白了只是利用查询结果不用依次数数来提高了性能。Skip虽然效率低一些但是通用一些,有序字段的查询,需要在设计分页的时候对这个字段做一些处理,起码要点了页码能获取到这个字段。这里我附加一个方式,就是两者的结合,我们可以拿每次展示的那页数据上的最后一个,结合Skip来处理分页,这样的话,相对来说更好一些。这里就不具体实现了。其他方式的性能比较和实现,欢迎大牛们来分享,十分感谢。另外本篇中如有纰漏和不足请留言指教。

热门栏目