博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于C#在Mongodb的Skip-Limit和Where-Limit的分页对比 并且含mongodb帮助类的源码
阅读量:6951 次
发布时间:2019-06-27

本文共 5236 字,大约阅读时间需要 17 分钟。

    最近在设计的日志服务中需要用到Mongodb这个Nosql数据库(),由于是用于纯存日志,而且日志量巨大,百万千万级的,所以需要用到它的分页查询。

         不过LZ也是刚刚接触这个数据库,不是很了解里面的命令语法,便在网上查了一些资料,结果 结果说mongodb自带的简单很方便的Skip方式的分页效率很低,无奈,无奈得用其他的,

        有多篇文章都推荐Where+Limit的方式分页,说他效率比Skip方式高多了,但是好多资料都是讲一些思路,并没有很具体,但是也很有帮助拉,现在简单的来讲一下这个分页思路(Skip的方式那么简单就不讲啦):

       假设一张表中(Mongodb用集合来代替)有如下条数据:1,3,4,5,6,7,8,9,20,30,50,51,52,59,60(仅仅标志该记录的ID号 你可以理解为主键)

      现在的也尺寸PageSize=4,那么

  •  第一页的数据为1,3,4,5,这个用where的方式解释为SQL语句为Select top 4 * from table where id>0 因为上一页是没有记录 所以用0来代替
  •  第二页的数据为6,7,8,9,20,这个用where的方式解释为SQL语句为Select top 4 * from table where id>5 这里的5就是上一页的最后一条记录
  •   第二页的数据为30,50,51,52,,这个用where的方式解释为SQL语句为Select top 4 * from table where id>20 这里的20就是第二页的最后一条记录

     这下就简单了,以后需要分页查询的时候传上一个ID号即可,Mongodb里面的思路也是这样 不过不一样的是c#用mongodb需要用其他驱动来查询数据,就用不了SQL语句了,简单的来贴一下代码

     

///         /// 分页查询 指定索引最后项-PageSize模式         ///         /// 
所需查询的数据的实体类型
/// 查询的条件 没有可以为null /// 索引名称 /// 最后索引的值 /// 分页的尺寸 /// 排序类型 1升序 -1降序 仅仅针对该索引 /// 指定的集合名称 ///
返回一个List列表数据
public List
Find
(IMongoQuery query, string indexName, object lastKeyValue, int pageSize, int sortType, string collectionName) { MongoCollection
mc = this._db.GetCollection
(collectionName); MongoCursor
mongoCursor = null; query = this.InitQuery(query); //判断升降序后进行查询 if (sortType > 0) { //升序 if (lastKeyValue != null) { //有上一个主键的值传进来时才添加上一个主键的值的条件 query = Query.And(query, Query.GT(indexName, BsonValue.Create(lastKeyValue))); } //先按条件查询 再排序 再取数 mongoCursor = mc.Find(query).SetSortOrder(new SortByDocument(indexName, 1)).SetLimit(pageSize); } else { //降序 if (lastKeyValue != null) { query = Query.And(query, Query.LT(indexName, BsonValue.Create(lastKeyValue))); } mongoCursor = mc.Find(query).SetSortOrder(new SortByDocument(indexName, -1)).SetLimit(pageSize); } return mongoCursor.ToList
(); }

    当然这个代码片段不怎么好看,估计各位读者看不大清,放心,下面会附源码下载(最恨那种代码贴一半都不知道说什么的人了)

    既然他们都说Skip效率差,那就自己测试看看呗,眼见为实嘛,

    我先在Mongodb从添加1000W条简单的数据,大数据量下测试才有有效果嘛,   

   

    给看下测试的控制台代码吧,都封装好了看的很方便哦,懒的展开的就不要了,很简单的

    

class Program    {        static MongoDBHelper db;        static void Main(string[] args)        {            //创建Mongodb的数据库实例            db = new MongoDBHelper();            #region 1000W条数据的初始化            //InitData();            #endregion            Console.WriteLine("Mongodb 中自己的Skip-Limit分页与自定义的Where-Limit分页效率测试(毫秒):");            //各种分页 尺寸的测试 具体注释我也不写了             PagerTest(1, 100);//这个测试忽略,估计第一次查询之后会相应的缓存下数据  导致之后的查询很快            PagerTest(3, 100);            PagerTest(30, 100);            PagerTest(300, 100);            PagerTest(300, 1000);            PagerTest(3000, 100);            PagerTest(30000, 100);            PagerTest(300000, 100);                        Console.ReadKey();        }        ///         /// 分页的测试        ///         /// 页码        /// 页尺寸        static void PagerTest(int pageIndex,int pageSize)        {            //分页查询条件空(封装中会转恒真条件) 排序条件空(转为ObjectId递增) 设定页码 也尺寸                        Console.WriteLine("页码{0},页尺寸{1}", pageIndex, pageSize);            Stopwatch sw1 = new Stopwatch();            sw1.Start();            List
list1 = db.Find
(null, pageIndex, pageSize, null); sw1.Stop(); Console.WriteLine("Skip-Limit方式分页耗时:{0}", sw1.ElapsedMilliseconds); Stopwatch sw2 = new Stopwatch(); sw2.Start(); //这里以Logid索引为标志 如果集合里面没有这些主键标志的话 完全可以使用自己的ObjectId来做 帮助类里面也是封装好的 //根据页码计算的LogId也只是简单的模拟 实际中这些LogId不一定会连续 这种方式分页一般不是传页码 而是传最后一个标志的值 List
list2 = db.Find
(null, "LogId", (pageIndex - 1) * pageSize, pageSize, 1); sw2.Stop(); Console.WriteLine("Where-Limit方式分页耗时:{0}\r\n", sw2.ElapsedMilliseconds); } ///
/// 初始化一下数据 /// static void InitData() { //创建 测试日志类的索引 索引的配置在LogInfo类的特性中 db.CreateIndex
(); //初始化日志的集合 List
list = new List
(); int temp = 0; //插入1000W条 测试的数据 for (int i = 1; i <= 10000000; i++) { list.Add(new LogInfo { LogId = i, Content = "content" + i.ToString(), CreateTime = DateTime.Now }); //temp计数 并作大于100的判断 if (++temp >= 100) { //大于等于100就清零 temp = 0; //用封装好的方法批量插入数据 db.Insert
(list); //插入数据之后将当前数据清空掉 list.Clear(); } } } }

     来看下最终的效率测试图吧:

      

       非常 ,very,超级明显的可以看出来Skip-Limit的分页效率有多低了吧,每当页码增加十倍时速度就降低十倍,在30W页的时候查询一次竟然要30秒,在大数据量下查询时完全受不了了,然而where-Limit的那种不管你多少页,速度还是那么快,最后一条的0秒是被四舍五入进0的,你看到了多块了吧。

      连续测试这几都是这几种情况,都不想把表格或者图来看了(第一条测试数据可以忽略,估计第一次查询会慢一点,以后会缓存)

      当然了,Where-Limit的方式查询是快,但是实际做起来还是有点麻烦得,不是传页码,而是传上一页的标志,并且并不是所有的集合都有自己的主键的,没有的话你可以用mongodb自带的ObjectId来查,他是默认的索引,速度也是很快的。

      建议如果是小量数据几千几万条的话 用Skip也无妨啦,毕竟是方便,如果数据量大的话千万别用,危险!!!!

      猛击我去看,可以直接运行哦,里面还有我自己写的Mongodb 查询帮助类

      参考的文章:

     

      

    

转载地址:http://dmkil.baihongyu.com/

你可能感兴趣的文章
1.6的锁优化(适应性自旋/锁粗化/锁削除/轻量级锁/偏向锁)
查看>>
使用 IntraWeb (17) - 基本控件之 TIWRadioButton、TIWRadioGroup、TIWCheckBox
查看>>
CSS解决高度自适应问题
查看>>
Thinkpad ACCESS CONNECTIONS异常解决
查看>>
ubuntu16.04 安装 操作 redis
查看>>
PHP文件上传-单文件上传函数
查看>>
通过SNMP获取接口速率 32位与64位的区别
查看>>
(1)Powershell简介
查看>>
Logtail提升采集性能
查看>>
asp.net5发神经一例 ------无法加载依赖
查看>>
uip中关于web服务器的简单例子
查看>>
Windows 10 ADK 1809 的变更 附下载地址
查看>>
知乎[披萨不就是个大饼铺点肉]问题延伸出的认知风格相关知识
查看>>
通过php 执行git pull 自动部署
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
用idea制作Javaweb程序遇到的过程
查看>>
想要成为python大神,这17个老司机收藏的国外免费学习网站不可错过!
查看>>
选型 - QA testing tools 2/26/2016
查看>>
Linux培训大纲
查看>>