mongo千万级数据优化

栏目: 数据库 · 发布时间: 6年前

内容简介:mongo采用的是单机部署,数据量1千万,需求是实现分页面,按照capTime倒叙排列,每页数据20条前端在查询下一页数据的时候讲,当前页数据的最后一条,capTime这个字段传过来,值是:1548482420,并且把该条数据对应的objectid也传过来,对应值:ObjectId("5bc5ce033b071d2fa84e60f4"),如果是相同的时间,对应的多条数据,要都传递过来,mongo查询的时候,添加条件capTime大于等于1548482420,并且不包含这几条数据,以下是对应的代码注:以上是

mongo采用的是单机部署,数据量1千万,需求是实现分页面,按照capTime倒叙排列,每页数据20条

  1. skip+limit 这是最传统的数据查询方式, db.getCollection('CapMotor').find().skip(9000000).sort({'capTime':1}).limit(20); skip后面是pageSize*pageIndex,limit后是pageSize 这种方式在数据量是百万的时候,还凑合着用,但是千万以后,就不可用了,我这边跟踪的查询时间是9s左右,明显不行,影响效率,建议采用第2中方法

  2. 前端传临界值id,查询添加条件,从当前位置往后截取,取20条

前端在查询下一页数据的时候讲,当前页数据的最后一条,capTime这个字段传过来,值是:1548482420,并且把该条数据对应的objectid也传过来,对应值:ObjectId("5bc5ce033b071d2fa84e60f4"),如果是相同的时间,对应的多条数据,要都传递过来,mongo查询的时候,添加条件capTime大于等于1548482420,并且不包含这几条数据,以下是对应的代码

//  数据查询下一页时:
db.getCollection('CapMotor').find({
    "$and":[
              {'capTime' :{ "$gte" :1548482420}},
              {'_id':{"$ne":ObjectId("5bc5ce033b071d2fa84e60f4")}}
          ]
    })
.sort({'capTime':1}).limit(20)

复制代码

注:以上是我考虑的按照某个字段排序,并且该字段的值有可能会有多个的情况,实际在开发中,该字段的值有可能是唯一的,对应的代码如下

//  数据查询下一页时:
db.getCollection('CapMotor').find({'capTime' :{ "$gt" :1539582402} }).sort({'capTime':1}).limit(20)
复制代码

第一种方法,前端可以指定调到首页,尾页,上下一页,中间指定页,但是前提是数据量不过百万的情况下; 第二种方法执行比较快,但是前端不能跳到指定的页数,首页,尾页,上下一页这种是可以的;

mongodb 分析器explain

本次是以3.4.15-49-g4ef027f为例,各个版本的执行计划差异较大

/* 1 */
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "bigdata.faceCapture",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "fcap_id" : {
                "$lt" : "fd129550-ced3-11e8-8ea8-1866daf63d9f"
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "fcap_id" : 1
                },
                "indexName" : "fcap_id_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "fcap_id" : []
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "fcap_id" : [ 
                        "[\"\", \"fd129550-ced3-11e8-8ea8-1866daf63d9f\")"
                    ]
                }
            }
        },
        "rejectedPlans" : []
    },
    "serverInfo" : {
        "host" : "master",
        "port" : 27017,
        "version" : "3.4.15-49-g4ef027f",
        "gitVersion" : "4ef027f98d5c00a0f4e507cbe39a22cab4c7a44c"
    },
    "ok" : 1.0
}
复制代码

重点关注queryPlanner里的winningPlan即可, explain.queryPlanner.winningPlan.stage:最优执行计划的stage,这里返回是FETCH,可以理解为通过返回的index位置去检索具体的文档(stage有数个模式,将在后文中进行详解)。

Explain.queryPlanner.winningPlan.inputStage:用来描述子stage,并且为其父stage提供文档和索引关键字。

explain.queryPlanner.winningPlan.stage的child stage,此处是IXSCAN,表示进行的是index scanning。

state各个值的解释如下: COLLSCAN :全表扫描

IXSCAN:索引扫描

FETCH::根据索引去检索指定document

SHARD_MERGE:各个分片返回数据进行merge

SORT:表明在内存中进行了排序(与前期版本的scanAndOrder:true一致)

SORT_MERGE:表明在内存中进行了 排序 后再合并

LIMIT:使用limit限制返回数

SKIP:使用skip进行跳过

IDHACK:针对_id进行查询

SHARDING_FILTER:通过mongos对分片数据进行查询

COUNT:利用db.coll.count()之类进行count运算

COUNTSCAN:count不使用用Index进行count时的stage返回

COUNT_SCAN:count使用了Index进行count时的stage返回

SUBPLA:未使用到索引的$or查询的stage返回

TEXT:使用全文索引进行查询时候的stage返回

集合faceCapture中有数据1千万条以上的数据,有复合索引fcap_time、fcap_dcid、person_id

{
    "fcap_time" : -1,
    "fcap_dcid" : 1,
    "person_id" : 1
}
复制代码

单行索引fcap_time、fcap_id

{
    "fcap_time" : 1
}
复制代码
{
    "fcap_id" : 1
}
复制代码

用关键字explain进行 sql 分析,发现如下问题:

// 走的是复合索引 注意索引的顺序,fcap_time" : -1,  "fcap_dcid" : 1,  "person_id" : 1
db.getCollection('faceCapture').find({'fcap_time' :{ "$gt" :1539745381}}).explain()
// 以下两个字段都是复合索引中,未走索引,
db.getCollection('faceCapture').find({'fcap_dcid' :{ "$lt" :"fd129550-ced3-11e8-8ea8-1866daf63d9f"}}).explain()
db.getCollection('faceCapture').find({'person_id' :{ "$lt" :"fd129550-ced3-11e8-8ea8-1866daf63d9f"}}).explain()
// 走的是索引 fcap_id" : -1, 
db.getCollection('faceCapture').find({'fcap_id' :{ "$lt" :"fd129550-ced3-11e8-8ea8-1866daf63d9f"}}).explain()
db.getCollection('faceCapture').find({'fcap_id' :{ "$lt" :"fd129550-ced3-11e8-8ea8-1866daf63d9f"}}).count()

复制代码

以下有如下结论

mongodb的索引也有最前缀原则,类似于 mysql 中的like关键字; 复合索引和单列索引中都有同一列,并且该列是位于复合索引的第一个位置时,默认走的是复合索引; 复合索引的非首位查询时,默认不走索引;


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP and MySQL Web Development (3rd Edition) (Developer's Library

PHP and MySQL Web Development (3rd Edition) (Developer's Library

Luke Welling、Laura Thomson / Sams / 2004-09-29 / USD 49.99

We've taken the best and made it even better. The third edition of the best-selling PHP and MySQL Web Development has been updated to include material and code on MySQL 5, PHP 5 and on PHPs object mod......一起来看看 《PHP and MySQL Web Development (3rd Edition) (Developer's Library》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具