Code前端首页关于Code前端联系我们

mongodb千万级数据分页优化及分析讲解

terry 2年前 (2023-09-26) 阅读数 73 #数据库

千万级数据分页优化

mongo采用单机部署,数据量千万级。要求获取分页,按照capTime闪回排列,每个数据页20条

  1. skip+limit 这是最传统的数据查询方法,db.getCollection('CapMotor').find() .skip( 9000000).sort({'capTime':1}).limit (20);skip 后跟 pageSize*pageIndex,limit 后跟 pageSize。这种方法在数据量达到百万级的时候还是有用的,但是过了千万级之后就不再可用了。我这里跟踪的题时间大概是9s左右,这显然是不可能的,而且影响效率。推荐使用第二种方法
  2. 前端传入临界值id,查询并添加条件,从当前位置截取,取20条

前端请求下一页数据时说一下当前页面的最后一条数据,capTime栏被跳过,值:1548482420,同时也传递了该数据对应的objectid,对应的值:ObjectId("5bc5ce033b071d2fa84e60f4"),如果相同的话有时,在某些匹配的数据块中必须传递。查询mongo时,添加capTime大于等于1548482420的条件,并且不包含数据chunk。下面是对应的代码

//  数据查询下一页时:
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)
复制代码

第一种方法,前端可以确定要转到首页。最后一页、前后一页、中间指定页,但仅限数据量小于100万时;第二种方法速度较快,但前端无法跳转到指定页码、首页、末页、上一页、下一页。这个有可能;

mongodb分析器讲解

本次以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中的winingPlan,定义.queryPlanner.winingPlan.stage:最优执行计划阶段。这里的返回是FETCH,可以理解为通过返回索引位置来检索特定的文档(该阶段有几种模式,后面会详细解释)。

Explain.queryPlanner.writingPlan.inputStage:用于解释子阶段,并为父阶段提供文档和关键字索引。

explain.queryPlanner.writingPlan.stage的子阶段,这是IXSCAN,表示正在执行索引扫描。每个状态值

的解释如下: COLLSCAN:全表扫描

IXSCAN:索引扫描

FETCH::从每个 shard_SHARD 中获取索引指定的文档数据_SHARD:用于合并

SORT :表示已经在内存中排序(对应之前版本中的 scanAndOrder:true)

SORT_MERGE:表示已经在内存中排序,然后合并

使用限制:LIMIT 返回次数

SKIP:使用skip

IDHACK:查询_id

SHARDING_FILTER:通过mongos 查询分片数据

ll。像db一样使用它。 COUNTSCAN:计数不使用索引计数时返回阶段

COUNT_SCAN:使用索引计数时返回阶段

SUBPLA:不使用索引时返回$或查询阶段

TEXT:全文索引询问时,阶段产生

。 faceCapture 集合中有超过 1000 万条数据。有复合索引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中的关键字相同;复合索引和单列索引有相同的列,并且该列位于复合索引的第一位,到达位置时默认使用复合索引;当查询复合索引的非首位置时,默认不使用该索引;

作者:LXH
来源:掘金

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门