ToB企服应用市场:ToB评测及商务社交产业平台

标题: MongoDB索引操作和执行计划Explain()详解 [打印本页]

作者: 冬雨财经    时间: 2023-8-11 17:26
标题: MongoDB索引操作和执行计划Explain()详解
主要是讲下Mongodb的索引的查看、创建、删除、类型说明,还有就是Explain执行计划的解释说明。 
 
可以转载,但请注明出处。  
之前自己写的SpringBoot整合MongoDB的聚合查询操作,感兴趣的可以点击查阅。
https://www.cnblogs.com/zaoyu/p/springboot-mongodb.html
数组相关的操作
https://www.cnblogs.com/zaoyu/p/mongodb_array_operator.html
 
一、索引操作

说明,下面的内容举例时,以"dailyTrip"collection为例。 字段内容如下:
  1. {
  2.     "_id" : ObjectId("63ec5a971ddbe429cbeeffe3"),  // object id
  3.     "car_type" : "Gett",  // string
  4.     "date" : ISODate("2016-04-01T00:00:00.000+0000"),  //ISODate
  5.     "trips" : 0.0,  // number
  6.     "monthly" : "NA", // string
  7.     "parent_type" : "Ride-hailing apps", // string
  8.     "monthly_is_estimated" : true, // boolean
  9.     "geo" : {  // object
  10.         "$concat" : [  // array
  11.             "$parent_type",
  12.             "$grouping"
  13.         ]
  14.     }
  15. }
复制代码
执行看看有5.17万条数据

1. 索引类型

 
2. 查看

语法:
  1. db.Collection.getIndexs();
复制代码
返回内容说明:
  1. [  // 返回一个数组,内容是所有索引
  2.     {
  3.         "v" : 2.0,  // 索引版本,可忽略
  4.         "key" : {  // 索引加在哪个字段,以及排序
  5.             "_id" : 1.0  // _id 是字段, 1.0是正序(升序), -1.0是倒序(倒序)
  6.         },
  7.         "name" : "_id_"  // 索引名,如果添加的时候没有指定,Mongo会自动生成。
  8.     }
  9. ]
复制代码
举例:
可以看到返回一个name为 _id_的索引。 作用于 _id上, 升序排列。

3. 创建

语法:
  1. db.collection.createIndex(keys, options)
  2. // 组合索引
  3. db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )  // 其中 <fieldN>是字段名 <typeN>是排序
  4. 注意:3.0.0 版本之前创建索引方法为 db.collection.ensureIndex()。 5.0之后ensureIndex() 已被移除。
复制代码
举例:
  1. // 创建单字段索引
  2. db.dailyTrip.createIndex({"car_type":1});
  3. // 返回结果
  4. {
  5.     "numIndexesBefore" : 1.0,  // 新建索引前的索引数
  6.     "numIndexesAfter" : 2.0,  // 新建索引后的索引数  
  7.     "createdCollectionAutomatically" : false,   // 一般情况下,如果该集合存在,这里就是返回false。如果指定的集合不存在,MongoDB 默认情况下会自动创建该集合,并在该集合上创建索引,此时返回true。
  8.     "ok" : 1.0  // 创建结果 1.0则是成功。返回0则说明报错了。
  9. }
  10. // 如果创建的字段的索引已经存在,则返回如下
  11. {
  12.     "numIndexesBefore" : 2.0,
  13.     "numIndexesAfter" : 2.0,
  14.     "note" : "all indexes already exist", // 提示已经存在
  15.     "ok" : 1.0
  16. }
  17. // 创建复合索引
  18. db.dailyTrip.createIndex({"parent_type":1, "car_type":1})
  19. // 也可以指定自定义索引名
  20. db.dailyTrip.createIndex({"parent_type":1, "car_type":1}, { name: "inx_parantType_carType" })  // 这里自己试验
  21. // 来自官方文档 https://www.mongodb.com/docs/manual/reference/command/createIndexes/
复制代码

 

 创建完毕后,再次查看当前索引情况

 
4. 删除

语法:
  1. 删除指定集合中所有索引:
  2. db.collection.dropIndexes();
  3. 删除指定集合中的具体索引:
  4. db.collection.dropIndex("索引名称");
复制代码
举例:
  1. // 删除指定索引
  2. db.dailyTrip.dropIndex("car_type_1");
  3. // 返回结果
  4. {
  5.     "nIndexesWas" : 3.0, // 指示在删除索引之前集合中存在的索引数量。
  6.     "ok" : 1.0
  7. }
  8. // 删除所有,自行尝试。 注意, 主键_id的索引是不会也不能被删除的。
  9. db.collection.dropIndexes();
复制代码

 
5. 修改

无法直接修改,如果需要调整索引字段、名称、组合索引的顺序,需要先删除原来索引,再新建索引。
6. 索引使用原则

7. 索引失效的情况

使用 explain() 方法可以查看查询计划和索引使用情况,帮助识别索引失效的原因,并进行相应的优化。
接下来对Explain方法做说明解释。
 
 
二、执行计划 Explain()

1. 什么是Explain()执行计划?

注意:explain()` 的输出非常详细,包含了大量的信息。因此,它在调试和优化查询时非常有用,但在生产环境中不应该频繁地使用,以避免对性能产生负面影响。
官方文档:
2. Explain的语法和使用
  1. 语法
  2. // 普通的语句,直接在语句后面加上explain,也可以挪到find的前面。  
  3. db.collection.find({}).explain(<optional verbosity mode>);
  4. // 对聚合pipeline的执行计划分析,explain放前面
  5. db.collection.explain(<optional verbosity mode>).aggregate([]);
  6. <optional verbosity mode> 是可选的输出模式。
  7. 如果什么都不写,比如  db.collection.find({"name"”":"onepiece"}).explain();  那么mongo会走默认模式 "queryPlanner"。
  8. 如果要指定模式,则直接加上,比如  db.collection.find({"name"”":"onepiece"}).explain("executionStats")
复制代码
explain有三种模式:
关于explain的参数可以参考官网: https://www.mongodb.com/docs/v5.0/reference/method/cursor.explain/#std-label-explain-cursor-method-verbosity
 
3. 三种模式下的说明和结果解释

3.1 queryPlanner 模式

运行查询优化器对当前的查询进行评估并选择一个最佳的查询计划,不执行实际语句。
 
下面三种模式均以这个查询语句为例:
  1. db.getCollection("dailyTrip").explain().find({"parent_type":"Ride-hailing apps"}, { _id:0});
复制代码
下面是一个执行的返回结果,我把详细内容先收起,可以看到返回的字段有哪些。

 
具体解释
  1. {
  2.     "explainVersion" : "1",  // 执行计划的版本,可以忽略
  3.     "queryPlanner" : {     //  queryPlanner,就是执行计划。 这部分重点看
  4.         "namespace" : "test.dailyTrip",  // 就是collection和所在db
  5.         "indexFilterSet" : false,   // 是否设置了索引过滤器集合,Filter决定了查询优化器对于某个查询将如何使用索引
  6.         "parsedQuery" : {    // 经过解析后的query内容。
  7.             "parent_type" : {
  8.                 "$eq" : "Ride-hailing apps"
  9.             }
  10.         },
  11.         "queryHash" : "8B8C334A",  // 查询的哈希值,
  12.         "planCacheKey" : "F910A33F", // 查询执行计划的缓存键
  13.         "maxIndexedOrSolutionsReached" : false, // 是否已达到最大索引【或】解决方案的限制。  跳过
  14.         "maxIndexedAndSolutionsReached" : false, // 表示是否已达到最大索引【和】解决方案的限制。 跳过
  15.         "maxScansToExplodeReached" : false, // 是否已达到最大扫描数的限制。 跳过
  16.         "winningPlan" : {   // 这个很关键,这里是最后底层选择的执行计划。   
  17.             "stage" : "PROJECTION_DEFAULT",  // stage 是指步骤 可以由stage名称看到具体做了什么。 projection是应用投影操作,选择所需的字段
  18.             "transformBy" : { // 具体投影内容  跳过
  19.                 "_id" : 0.0
  20.             },
  21.             "inputStage" : { // 执行阶段的子阶段,这里是一个FETCH的子过程
  22.                 "stage" : "FETCH",   // FETCH是 从索引中获取文档数据。
  23.                 "inputStage" : { // 其中一个阶段,具体操作。 这里面的东西是重点要看的。
  24.                     "stage" : "IXSCAN", // 这里是说使用索引进行扫描,通常表示优化的查询。
  25.                     "keyPattern" : { // 表示下面的索引字段的排列方式,1.0正序,-1.0倒序。
  26.                         "parent_type" : 1.0,
  27.                         "car_type" : 1.0
  28.                     },
  29.                     "indexName" : "parent_type_1_car_type_1", // 用到的索引名称
  30.                     "isMultiKey" : false, // 是否为多键索引。 如果为 true,表示索引包含数组值
  31.                     "multiKeyPaths" : { // 如果索引是多键索引,这个属性将会包含索引中包含数组值的字段路径。本例中的索引不是多键索引,因此下面的字段为空数组。
  32.                         "parent_type" : [
  33.                         ],
  34.                         "car_type" : [
  35.                         ]
  36.                     },
  37.                     "isUnique" : false, // 是否为唯一索引
  38.                     "isSparse" : false, // 是否为稀疏索引
  39.                     "isPartial" : false, // 是否为部分索引
  40.                     "indexVersion" : 2.0, // 索引版本
  41.                     "direction" : "forward", // 索引的遍历方向
  42.                     "indexBounds" : {  // 当前查询具体使用的索引
  43.                         "parent_type" : [
  44.                             "["Ride-hailing apps", "Ride-hailing apps"]"
  45.                         ],
  46.                         "car_type" : [
  47.                             "[MinKey, MaxKey]"
  48.                         ]
  49.                     }
  50.                 }
  51.             }
  52.         },
  53.         "rejectedPlans" : [  // 底层优化器拒绝的计划,没有执行的计划。  
  54.         ]
  55.     },
  56.     "command" : {   // 语句具体涉及到的命令、collection、DB
  57.         "find" : "dailyTrip",  // 表名 从哪个collection中查找
  58.         "filter" : {   // 哪个阶段,这里就是过滤
  59.             "parent_type" : "Ride-hailing apps"
  60.         },
  61.         "projection" : {   // 投影 控制要返回的字段
  62.             "_id" : 0.0
  63.         },
  64.         "$db" : "test"   // 库
  65.     },
  66.     "serverInfo" : {     // 服务器信息   
  67.         "host" : "onepiece-pc",  // mongo的示例主机名称
  68.         "port" : 27017.0, //  端口
  69.         "version" : "5.0.9", // mongodb的版本
  70.         "gitVersion" : "6f7dae919422dcd7*****************1ad00e6"  // 这里是git版本,这里无关紧要,我脱敏了。
  71.     },
  72.     "serverParameters" : {   // 服务器的参数,各种缓存大小、最大阈值设置,暂时和我们这里说的内容无关,跳过。
  73.         "internalQueryFacetBufferSizeBytes" : 104857600.0,
  74.         "internalQueryFacetMaxOutputDocSizeBytes" : 104857600.0,
  75.         "internalLookupStageIntermediateDocumentMaxSizeBytes" : 104857600.0,
  76.         "internalDocumentSourceGroupMaxMemoryBytes" : 104857600.0,
  77.         "internalQueryMaxBlockingSortMemoryUsageBytes" : 104857600.0,
  78.         "internalQueryProhibitBlockingMergeOnMongoS" : 0.0,
  79.         "internalQueryMaxAddToSetBytes" : 104857600.0,
  80.         "internalDocumentSourceSetWindowFieldsMaxMemoryBytes" : 104857600.0
  81.     },
  82.     "ok" : 1.0
  83. }
复制代码
3.2 executionStats模式
  1. db.getCollection("dailyTrip").find({"parent_type":"Ride-hailing apps"}, { _id:0}).explain("executionStats");
复制代码
运行查询优化器对当前的查询进行评估并选择一个最佳的查询计划进行执行,在执行完毕后返回这个最佳执行计划执行完成时的相关统计信息。

 
  1. {
  2.     "explainVersion" : "1",
  3.     "queryPlanner" : {
  4.         // ... 同上,省略。
  5.         "parsedQuery" : {
  6.            // ... 同上,省略。
  7.         },
  8.         // ... 同上,省略。
  9.         "winningPlan" : {
  10.            // ... 同上,省略。
  11.         }
  12.         "rejectedPlans" : [
  13.            // ... 同上,省略。
  14.         ]
  15.     },
  16.     "executionStats" : { // 重点留意这里面的内容
  17.         "executionSuccess" : true,  // 执行结果
  18.         "nReturned" : 23010.0,  // 返回的文档数
  19.         "executionTimeMillis" : 70.0, // 执行耗时 ms
  20.         "totalKeysExamined" : 23010.0,  // 扫描了的索引总数
  21.         "totalDocsExamined" : 23010.0,  // 总的扫描文档数
  22.         "executionStages" : {  // 执行stage 里面会有具体每个stage的详细
  23.             "stage" : "PROJECTION_DEFAULT",  // 阶段类型
  24.             "nReturned" : 23010.0,
  25.             "executionTimeMillisEstimate" : 10.0, // 预估执行时间  ms
  26.             "works" : 23011.0,  // 阶段中扫描任务数
  27.             "advanced" : 23010.0, // 阶段中向上提交数量
  28.             "needTime" : 0.0, // 阶段中定位索引位置所需次数
  29.             "needYield" : 0.0, // 阶段中获取锁等待时间
  30.             "saveState" : 23.0, // :表示在查询执行过程中,保存中间状态所花费的时间 ms
  31.             "restoreState" : 23.0, // 表示在查询执行过程中,恢复之前保存的中间状态所花费的时间 ms
  32.             "isEOF" : 1.0, // 阶段中是否到达流的结束位,对于limit限制符的查询可能为0
  33.             "transformBy" : { // 表示查询计划是否使用了投影操作来转换结果
  34.                 "_id" : 0.0
  35.             },
  36.             "inputStage" : { // 执行阶段的子阶段,这里是一个fetch的子过程
  37.                 "stage" : "FETCH", // 内容差不多
  38.                 "nReturned" : 23010.0,
  39.                 "executionTimeMillisEstimate" : 4.0,
  40.                 "works" : 23011.0,
  41.                 "advanced" : 23010.0,
  42.                 "needTime" : 0.0,
  43.                 "needYield" : 0.0,
  44.                 "saveState" : 23.0,
  45.                 "restoreState" : 23.0,
  46.                 "isEOF" : 1.0,
  47.                 "docsExamined" : 23010.0,
  48.                 "alreadyHasObj" : 0.0,
  49.                 "inputStage" : { //  子阶段,ixscan子过程
  50.                     "stage" : "IXSCAN",
  51.                     "nReturned" : 23010.0,
  52.                     "executionTimeMillisEstimate" : 4.0,
  53.                     "works" : 23011.0,
  54.                     "advanced" : 23010.0,
  55.                     "needTime" : 0.0,
  56.                     "needYield" : 0.0,
  57.                     "saveState" : 23.0,
  58.                     "restoreState" : 23.0,
  59.                     "isEOF" : 1.0,
  60.                     "keyPattern" : {
  61.                         "parent_type" : 1.0,
  62.                         "car_type" : 1.0
  63.                     },
  64.                     "indexName" : "parent_type_1_car_type_1",
  65.                     "isMultiKey" : false,
  66.                     "multiKeyPaths" : {
  67.                         "parent_type" : [
  68.                         ],
  69.                         "car_type" : [
  70.                         ]
  71.                     },
  72.                     "isUnique" : false,
  73.                     "isSparse" : false,
  74.                     "isPartial" : false,
  75.                     "indexVersion" : 2.0,
  76.                     "direction" : "forward",
  77.                     "indexBounds" : {
  78.                         "parent_type" : [
  79.                             "["Ride-hailing apps", "Ride-hailing apps"]"
  80.                         ],
  81.                         "car_type" : [
  82.                             "[MinKey, MaxKey]"
  83.                         ]
  84.                     },
  85.                     "keysExamined" : 23010.0,
  86.                     "seeks" : 1.0,
  87.                     "dupsTested" : 0.0,
  88.                     "dupsDropped" : 0.0
  89.                 }
  90.             }
  91.         }
  92.     },
  93.     "command" : { // ... 同上,省略。
  94.     },
  95.     "serverInfo" : { // ... 同上,省略。
  96.     },
  97.     "serverParameters" : {// ... 同上,省略。
  98.     },
  99.     "ok" : 1.0
  100. }
复制代码
3.3 allPlansExecution模式
  1. // 调用explain("allPlansExecution"), allPlansExecution 模式,执行所有的方案,并输出结果。
  2. db.getCollection("dailyTrip").find({"parent_type":"Ride-hailing apps"}, { _id:0}).explain("allPlansExecution");
复制代码
allPlansExecution相比executionStats,其他的备选执行计划也会去执行,并统计结果出来。 会存放在 executionStats中。
即按照最佳的执行计划执行以及列出统计信息, 如果有多个查询计划,还会列出这些非最佳执行计划部分的统计信息。

 
  1. {
  2.     "explainVersion" : "1",
  3.     "queryPlanner" : {
  4.         "namespace" : "test.dailyTrip",
  5.         "indexFilterSet" : false,
  6.         "parsedQuery" : {
  7.             "parent_type" : {
  8.                 "$eq" : "Ride-hailing apps"
  9.             }
  10.         },
  11.         "maxIndexedOrSolutionsReached" : false,
  12.         "maxIndexedAndSolutionsReached" : false,
  13.         "maxScansToExplodeReached" : false,
  14.         "winningPlan" : {
  15.            // ... 同上,省略。
  16.         },
  17.         "rejectedPlans" : [
  18.            // ... 同上,省略。
  19.         ]
  20.     },
  21.     "executionStats" : {
  22.         "executionSuccess" : true,
  23.         "nReturned" : 23010.0,
  24.         "executionTimeMillis" : 68.0,
  25.         "totalKeysExamined" : 23010.0,
  26.         "totalDocsExamined" : 23010.0,
  27.         "executionStages" : {
  28.          // 这里的executionStage和2.2的executionStats中的executionstages一样,参考那里。
  29.         },
  30.         "allPlansExecution" : [  // 重点:allPlansExecution 如果有其他执行计划,那么会在这里把执行统计结果放出来。   
  31.         ]
  32.     },
  33.     "command" : {// ... 同上,省略。
  34.     },
  35.     "serverInfo" : {// ... 同上,省略。
  36.     },
  37.     "serverParameters" : {// ... 同上,省略。
  38.     },
  39.     "ok" : 1.0
  40. }
复制代码
Stage参数值

参考文档

https://www.cnblogs.com/littleatp/p/8419678.html
 
4. 查询优化思路

 
完。
感谢查阅,希望对你有帮助,点个赞再走呗~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4