mongo千万级数据优化

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

内容简介: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关键字; 复合索引和单列索引中都有同一列,并且该列是位于复合索引的第一个位置时,默认走的是复合索引; 复合索引的非首位查询时,默认不走索引;


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

查看所有标签

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

MySQL性能调优与架构设计

MySQL性能调优与架构设计

简朝阳 / 2009-6 / 59.80元

《MySQL性能调优与架构设计》以 MySQL 数据库的基础及维护为切入点,重点介绍了 MySQL 数据库应用系统的性能调优,以及高可用可扩展的架构设计。 全书共分3篇,基础篇介绍了MySQL软件的基础知识、架构组成、存储引擎、安全管理及基本的备份恢复知识。性能优化篇从影响 MySQL 数据库应用系统性能的因素开始,针对性地对各个影响因素进行调优分析。如 MySQL Schema 设计的技巧......一起来看看 《MySQL性能调优与架构设计》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

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

HSV CMYK互换工具