mongodb 查询优化方法

mongodb 查询优化方法:

基本方法:
    1 尽可能添加索引,走索引查询,防止回表可以构建联合索引
    2 索引不宜过多,一般不超过7个。看业务情况。写越多,索引越少。或垂直拆分表,或做数据备份。主写从查。
    3 加缓存,能部分情况下防止尖刺产生。如果是冷数据,那么业务上一般是允许较慢的查询。
    4 简单表亿级数据量,4c8g阿里云副本集。 单次查询100ms以内。
    5 联合索引最左匹配(少用索引交集)


1 通过解释语言或者查看慢日志
2 关注以下字段:
    keysExamined 索引扫的行数(越小越好)
    keysExaminedBySizeInBytes 索引查询到的数据量(越小越好)
    docsExamined 文档扫的行数(越小越好)
    docsExaminedBySizeInBytes 文档查询到的数据量(越小越好)
    numYield 让步次数(越小越好)
    storage.timeReadingMicros 从磁盘中读取的耗时 (越小越好)
    planSummary 执行的方案 (尽可能走索引)
    nreturned 返回的行数 (看情况返回,一般分页为20个)
    responseLength 返回的字节大小 (越小越好,可以只拿需要的数据)

以下为各种场景的举例:

1 COLLSCAN转为IXSCAN

如下:
    单表83203行数据
    全表扫描COLLSCAN,扫了全部文档,拉取文档83203多个。并且是从db的磁盘中拉取的数据且耗时5164微秒。由于耗时多,且有写语句,导致让步次数650次。总耗时117ms。
    优化方案:给ts添加索引

{
    "op": "query",
    "ns": "***********",
    "command": {
        "find": "***********",
        "filter": {},
        "sort": {
            "ts": -1
        },
        "limit": 20,
    },
    "keysExamined": 0,
    "keysExaminedBySizeInBytes": 0,
    "docsExamined": 83203,
    "docsExaminedBySizeInBytes": 4100295,
    "hasSortStage": true,
    "numYield": 650,
    "nreturned": 20,
    "storage": {
        "data": {
            "bytesRead": {
                "$numberLong": "4519673"
            },
            "timeReadingMicros": {
                "$numberLong": "5164"
            }
        }
    },
    "responseLength": 1378,
    "millis": 117,
    "planSummary": "COLLSCAN"
}

2 大表(3.7亿数据),IXSCAN查询

如下:
    单表379840512行数据
    索引命中,已经没有优化空间。numYield让步次数较少,证明是写较少。每批次500个。
    优化方案: 
        1 减少batchSize值。每批少拿,多拉几次。
        2 数据横向切分(试情况而定)

{
    "op": "getmore",
    "command": {
        "getMore": {
        },
        "batchSize": 500,
    },
    "originatingCommand": {
        "find": "********",
        "filter": {
            "device.$id": {
                "$oid": "5e3f999ba659686487339268"
            }
        },
        "sort": {
            "ts": -1
        },
        "batchSize": 500,
    },
    "keysExamined": 402,
    "keysExaminedBySizeInBytes": 11658,
    "docsExamined": 402,
    "docsExaminedBySizeInBytes": 228458,
    "cursorExhausted": true,
    "numYield": 10,
    "nreturned": 402,
    "flowControl": {},
    "storage": {
        "data": {
            "bytesRead": {
                "$numberLong": "41694033"
            },
            "timeReadingMicros": {
                "$numberLong": "97588"
            }
        }
    },
    "responseLength": 230584,
    "millis": 113,
    "planSummary": "IXSCAN { device.$id: -1, ts: -1 }",
    "replRole": {
        "stateStr": "PRIMARY",
        "_id": 13
    }
}

3 IXSCAN查询,但是索引没有走对

如下:
    使用了成本最小的索引
    解决方案:
        1 不存在更好的索引的时候:精确创建索引
        2 存在更好的索引的时候:
            2.1 hint明确指明使用
            2.2 可能索引区分度很低,这时候意义不大,分库或者改变数据模型,或者上缓存

{
    "op": "query",
    "command": {
        "find": "**************",
        "filter": {
            "apply.$id": {
                "$oid": "5714e03ad92cc517ea3e29de"
            }
        },
        "limit": {
            "$numberLong": "21"
        },
        "sort": {
            "time.create": -1
        },
    },
    "keysExamined": 1412,
    "keysExaminedBySizeInBytes": 40948,
    "docsExamined": 1412,
    "docsExaminedBySizeInBytes": 1805370,
    "hasSortStage": true,
    "cursorExhausted": true,
    "numYield": 15,
    "nreturned": 21,
    "storage": {
        "data": {
            "bytesRead": {
                "$numberLong": "45511371"
            },
            "timeReadingMicros": {
                "$numberLong": "149800"
            }
        }
    },
    "responseLength": 39381,
    "protocol": "op_msg",
    "millis": 162,
    "planSummary": "IXSCAN { apply.$id: 1, time.update: -1 }",
    "replRole": {
        "stateStr": "PRIMARY",
        "_id": 13
    }
}

4 交集索引

如下:
    存在deviceid的索引,subscriber.key的索引,但是mondo并不会使用,会使用其他的。
    优化方案:
        使用联合索引替代,核心业务一定要

{
    "op": "query",
    "ns": "*******",
    "command": {
        "find": "**********",
        "filter": {
            "deviceid": {
                "$oid": "5d6b49474cfed7134d9c228e"
            },
            "subscriber.key": "5d86e1c062100f57d1c2cecf_8562"
        },
    },
    "keysExamined": 1628,
    "keysExaminedBySizeInBytes": 83028,
    "docsExamined": 1628,
    "docsExaminedBySizeInBytes": 363910,
    "cursorExhausted": true,
    "numYield": 25,
    "nreturned": 2,
    "responseLength": 679,
    "millis": 137,
    "planSummary": "IXSCAN { subscriber.key: -1, ts: -1 }",
}

5 超大表ixscan索引命中

如下:
    主键查询,20亿数据
    优化方案:
        1 水平分库
        2 使用缓存

{
    "op": "query",
    "ns": "*******",
    "command": {
        "find": "**********",
        "filter": {
            "_id": {
                "$oid": "5d6b49474cfed7134d9c228e"
            }
        },
    },
    "keysExamined": 1,
    "keysExaminedBySizeInBytes": 243,
    "docsExamined": 1,
    "docsExaminedBySizeInBytes": 243,
    "cursorExhausted": true,
    "numYield": 10,
    "nreturned": 1,
    "responseLength": 679,
    "millis": 111,
    "planSummary": "IXSCAN { _id: -1 }",
}

6 ixscan索引命中,但是写多

如下:
    主键查询,2亿数据,写也多,导致numYield较多。
    优化方案:
        1 垂直分库
        2 使用缓存

{
    "op": "query",
    "ns": "*******",
    "command": {
        "find": "**********",
        "filter": {
            "_id": {
                "$oid": "5d6b49474cfed7134d9c228e"
            }
        },
    },
    "keysExamined": 1,
    "keysExaminedBySizeInBytes": 269,
    "docsExamined": 1,
    "docsExaminedBySizeInBytes": 63,
    "cursorExhausted": true,
    "numYield":257,
    "nreturned": 1,
    "responseLength": 679,
    "millis": 101,
    "planSummary": "IXSCAN { _id: -1 }",
}

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值