06-MongoDB 查询索引优化-1-分析查询计划

查询计划

  • 通过查询计划我们可以看到很多查询的关键因素,尤其是慢查询,mongodb在数据量很大的时候,很可能就需要针对业务场
    景去优化索引了,但是在优化索引之前我们需要查询执行计划,先看我们的查询为什么慢。关于查询计划网上有很多详细的分
    析我就不列举了,因为整个计划详情非常多,这一篇文章我只给出计划详情中的几个我们首先要关注的指标,在下一篇索引优
    化中结合业务场景给出具体的优化示例。如果想详细了解查询计划的,可以参阅我的参考里面的MongoDB干货系列。

一、查看查询计划

  • 在执行mongodb的语句的时候,我们在最后加上explain(“executionStats”),然后就能看到执行计划的输出,执行计划也是
    以json格式输出的。命令示例如下:
db.getCollection('multobj').find({"targetType":"face"}).sort({time:-1}).limit(100).explain("executionStats")
  • 输出执行计划后,执行计划的内容是很多的,因此我们刚刚开始可能没法全部都去关注,但是有几个点基本上是我们首先需要
    关注的,后面我们一一来盘点。

二、查询计划核心点

  • 下面为了节约篇幅,我只截取了执行计划中的一小部分,如果对执行计划不熟悉可以先了解,或者直接在执行计划里面搜索关
    键字。

2.1 耗时多久?

  • 在执行计划中我们可以看到执行耗时,在executionStats的executionTimeMillis字段,展示的就是执行耗时:
 "executionStats" : {
        "nReturned" : 10,
        "executionTimeMillis" : 5,//耗时
        "totalKeysExamined" : 10,
        "totalDocsExamined" : 10,

2.2 扫描数

  • 我们还关心一次查询扫描了多少次记录,比如我们查询10条,那么这次查询扫描的是索引还是文档,扫描的数量和我们查询的数量
    相差多少?理想的情况是我们扫描的索引数=扫描的文档数=我们需要查询的数目,在查询计划中就是上面展示的。最佳情况是
    nReturned=totalDocsExamined=totalKeysExamined,或者nReturned=totalDocsExamined<totalKeysExamined,因为扫描索引是在内存
    中,大一点可以接受,但是totalDocsExamined比nReturned大很多,就需要认真对待这次查询了,数据量大的时候很可能会慢。
 "executionStats" : {
        "nReturned" : 10, //返回记录条数
        "executionTimeMillis" : 5, //耗时
        "totalKeysExamined" : 10,  //扫描的索引数目
        "totalDocsExamined" : 10,  //扫描的文档数目

2.3 stage字段

  • 我们很多时候查询的时候都会指定排序方式,比如时间,权重类字段等。如下是compass客户端工具给我们展示查询计划的时候,他会把这个几个
    字段的结果以图形的方式呈现,也可以看原始的json数据,比较直观。
    image

  • 内存排序的弊端是什么?因为数据量大的时候,比如你查询近1月的数据,一个月有几千万的数据,放到内存排序是不可能的。如果并行查询都来占据内存后果可想
    而知,而且mongodb内部貌似有32MB的限制。如何查看是否使用了内存排序?我们查看winningPlan.inputStage.stage这个字段的值,如下所示:

 "winningPlan" : {
                        "stage" : "LIMIT",
                        "limitAmount" : 10,
                        "inputStage" : {
                            "stage" : "FETCH",
                            "inputStage" : {
                                "stage" : "IXSCAN",
  • 这里嵌套了好几层,如果字段的值是SORT,那就说明使用了内存排序,这样的查询需要优化。通常比较多见的是FETCH,IXSCAN,我列举几种常见的如下,尤其注意不要出
    现不能接受的:
stage字段值含义备注
FETCH根据索引去检索指定document可以接受
IXSCAN索引扫描可以接受
COUNT_SCANcount使用索引进行计数可以接受
LIMIT使用limit限制返回数可以接受
SKIPskip跳过可以接受
PROJECTION限定返回字段可以接受
SORT内存排序不能接受
COLLSCAN全表扫描不能接受
COUNTSCANcount不使用索引进行计数不能接受

2.4 使用了什么索引?

  • 我们在数据库中可能建立了很多索引,一次查询引擎会选择一个可用的索引,我们通过查询计划可以看到。我们会看到有
    winningPlan和rejectedPlans,在winningPlans里面找到indexBounds,就可以看到执行引擎选择的索引,如下的查询可以看到
    使用了targetType+time的组合索引,拒绝了targetType字段的单键索引。

SQL:db.getCollection('multobj').find({targetType:"face"}).sort({time:-1}).limit(10).explain("executionStats")

"winningPlan" : {
                        "stage" : "LIMIT",
                        "limitAmount" : 10,
                        "inputStage" : {
                            "stage" : "FETCH",
                            "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                    "targetType" : 1,
                                    "time" : -1
                                },
                                "indexName" : "targetType_1_time_-1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                    "targetType" : [],
                                    "time" : []
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                    "targetType" : [ 
                                        "[\"face\", \"face\"]"
                                    ],
                                    "time" : [ 
                                        "[MaxKey, MinKey]"
                                    ]
                                }
                            }
                        }
                    },
                    
"rejectedPlans" : [ 
                        {
                            "stage" : "SORT",
                            "sortPattern" : {
                                "time" : -1.0
                            },
                            "limitAmount" : 10,
                            "inputStage" : {
                                "stage" : "SORT_KEY_GENERATOR",
                                "inputStage" : {
                                    "stage" : "FETCH",
                                    "inputStage" : {
                                        "stage" : "IXSCAN",
                                        "keyPattern" : {
                                            "targetType" : 1
                                        },
                                        "indexName" : "targetType_1",
                                        "isMultiKey" : false,
                                        "multiKeyPaths" : {
                                            "targetType" : []
                                        },
                                        "isUnique" : false,
                                        "isSparse" : false,
                                        "isPartial" : false,
                                        "indexVersion" : 2,
                                        "direction" : "forward",
                                        "indexBounds" : {
                                            "targetType" : [ 
                                                "[\"face\", \"face\"]"
                                            ]
                                        }
                                    }
                                }
                            }
                        }
                    ]

三、总结

  • 本篇文章我们只是简单了列举了mongodb查询时几个关键的参数,并未进行详细的分析,最后的参考文章中已有对查询计划有详细分析
    的文章,因为我是按照自己使用中的经验来写,因此未使用到的就不做详细分析了,有需要可以参考对应的文章。在下一篇文章我会针对
    一个具体我使用的业务场景来优化索引,并对比前后的查询计划中的不同点。
  • 这里推荐2款mongodb的客户端工具,一个是robo.3t,这个工具比较直观,需要自己写sql。另一个是Mongodb Compass,这个工具对分析
    执行计划比较好,尤其是新手,他把执行计划里面的几个关键信息都展示出来了,比如各个阶段的耗时,总耗时,使用哪个索引,是否使用
    了内存排序等。
    image
  • 如上图中给出了查询的几个关键信息,以及每个阶段的耗时,比如limit,fetch,ixscan等,detail里面有详细的信息,也可以查看原始的json,
    对于查询计划不熟悉的时候,可以较为傻瓜式的根据这些信息来看查询的情况是否乐观。

四、参考

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值