QuerySolution 执行计划(过滤条件filter、sort排序等都属于计划的一部分)
    QueryPlaner 生成执行计划模块(explain()生成执行计划,不实际执行)
    PlanExecutor 运行执行计划模块,同时充当优化器(Optimizer)的角色(explain(executionStats)实际运行执行计划)

    image.png

    • 1). Client按照MongoDB的网络协议,请求建立连接,并友单独新建的thread处理所有请求。
    • 2). 有些Query(如insert),本身不需要执行计划和优化,这直接通过接口和引擎交互(通过RecordStore写表)
    • 3). Query会进行简单的处理(标准化),并构造一些上下文数据结构变成CanonicalQuery(标准化Query)。
    • 4). Plan模块会负责生成该Query的多个执行计划,然后丢给Optimizer去选择最优的,丢给PlanExecutor。
    • 5). PlanExecutor按照执行计划一步一步迭代,获得最终的数据(或执行update修改数据)。
      在此流程中:
    • Plan如果只关联到单个或零个索引,这只生成一个执行计划,如果发现有多个索引或者索引有重叠,这可能生成多个执行计划。
    • Optimizer只在多个执行计划时,才会介入。

    explain() 可以接收不同的参数,通过设置不同参数我们可以查看更详细的查询计划。
    queryPlanner:是默认参数
    explain() 设置参数的三种模式
    1 queryPlanner
    不会真正的执行查询,只是分析查询,选出winning plan。
    2 executionStats
    返回winning plan的关键数据。
    executionTimeMillis该query查询的总体时间。
    3 allPlansExecution
    执行所有的plans。

    1. > db.getCollection("stepsDetail").find( { "ssoid" : "670274649", "modifiedTime" : NumberLong(1619671871306) } ).explain()
    2. {
    3. "queryPlanner" : {
    4. "mongosPlannerVersion" : 1,
    5. "winningPlan" : {
    6. "stage" : "SINGLE_SHARD",
    7. "shards" : [
    8. {
    9. "shardName" : "sport-health_oXHqoVcC_shard_2", //分片
    10. "connectionString" : "sport-health_oXHqoVcC_shard_2/10.177.233.79:20000,10.177.233.80:20000,10.177.233.81:20000",//链接字符串
    11. "serverInfo" : { //MongoDB服务器信息
    12. "host" : "10-177-233-81.mongodb-fatpod-sport-health.dgtest01",
    13. "port" : 20000,
    14. "version" : "3.6.13",
    15. "gitVersion" : "db3c76679b7a3d9b443a0e1b3e45ed02b88c539f"
    16. },
    17. "plannerVersion" : 1, //查询计划版本
    18. "namespace" : "sporthealth.stepsDetail", //要查询的集合
    19. "indexFilterSet" : false, //boolean 查询模型是否使用索引过滤
    20. "parsedQuery" : {//查询条件
    21. "$and" : [
    22. {
    23. "modifiedTime" : {
    24. "$eq" : NumberLong("1619671871306")
    25. }
    26. },
    27. {
    28. "ssoid" : {
    29. "$eq" : "670274649"
    30. }
    31. }
    32. ]
    33. },
    34. "winningPlan" : { //最佳执行计划
    35. "stage" : "FETCH",//最优执行计划的stage
    36. "inputStage" : {
    37. "stage" : "IXSCAN",//查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询
    38. "keyPattern" : {//所扫描的index内容
    39. "ssoid" : 1,
    40. "modifiedTime" : -1
    41. },
    42. "indexName" : "ssoid_1_modifiedTime_-1",//winning plan所选用的index
    43. "isMultiKey" : false,//是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true
    44. "multiKeyPaths" : {
    45. "ssoid" : [ ],
    46. "modifiedTime" : [ ]
    47. },
    48. "isUnique" : false,
    49. "isSparse" : false,
    50. "isPartial" : false,
    51. "indexVersion" : 2,
    52. "direction" : "forward",//此query的查询顺序,此处是forward,如果用了.sort({ssoid:-1})将显示backward
    53. "indexBounds" : {//winningplan所扫描的索引范围
    54. "ssoid" : [
    55. "[\"670274649\", \"670274649\"]"
    56. ],
    57. "modifiedTime" : [
    58. "[1619671871306, 1619671871306]"
    59. ]
    60. }
    61. }
    62. },
    63. "rejectedPlans" : [//其他执行计划(非最优而被查询优化器reject的)的详细返回,其中具体信息与winningPlan的返回中意义相同
    64. {
    65. "stage" : "FETCH",
    66. "filter" : {//过滤条件
    67. "$and" : [
    68. {
    69. "ssoid" : {
    70. "$eq" : "670274649"
    71. }
    72. },
    73. {
    74. "modifiedTime" : {
    75. "$eq" : NumberLong("1619671871306")
    76. }
    77. }
    78. ]
    79. },
    80. "inputStage" : {
    81. "stage" : "IXSCAN",
    82. "keyPattern" : {//所扫描的index内容
    83. "ssoid" : "hashed"
    84. },
    85. "indexName" : "ssoid_hashed",//所选用的index
    86. "isMultiKey" : false,
    87. "isUnique" : false,
    88. "isSparse" : false,
    89. "isPartial" : false,
    90. "indexVersion" : 2,
    91. "direction" : "forward",
    92. "indexBounds" : {
    93. "ssoid" : [
    94. "[-6533328432691190449, -6533328432691190449]"
    95. ]
    96. }
    97. }
    98. },
    99. {
    100. "stage" : "FETCH",
    101. "filter" : { //过滤条件
    102. "modifiedTime" : {
    103. "$eq" : NumberLong("1619671871306")
    104. }
    105. },
    106. "inputStage" : {
    107. "stage" : "IXSCAN",
    108. "keyPattern" : { //所扫描的index内容
    109. "ssoid" : 1,
    110. "clientDataId" : 1
    111. },
    112. "indexName" : "ssoid_1_clientDataId_1",
    113. "isMultiKey" : false,
    114. "multiKeyPaths" : {
    115. "ssoid" : [ ],
    116. "clientDataId" : [ ]
    117. },
    118. "isUnique" : true,
    119. "isSparse" : false,
    120. "isPartial" : false,
    121. "indexVersion" : 2,
    122. "direction" : "forward",
    123. "indexBounds" : {
    124. "ssoid" : [
    125. "[\"670274649\", \"670274649\"]"
    126. ],
    127. "clientDataId" : [
    128. "[MinKey, MaxKey]"
    129. ]
    130. }
    131. }
    132. }
    133. ]
    134. }
    135. ]
    136. }
    137. },
    138. "ok" : 1, //操作状态
    139. "operationTime" : Timestamp(1619683463, 3),////操作时间
    140. "$clusterTime" : {
    141. "clusterTime" : Timestamp(1619683468, 1),
    142. "signature" : {
    143. "hash" : BinData(0,"uCHZd6sSRBNKDLXw1xUi2mHErmo="),
    144. "keyId" : NumberLong("6915417759157321730")
    145. }
    146. }
    147. }

    Stage状态分析
    COLLSCAN 全表扫描
    IXSCAN 扫描索引
    FETCH 根据索引去检索指定document
    SHARD_MERGE 将各个分片返回数据进行merge
    SORT 表明在内存中进行了排序
    LIMIT 使用limit限制返回数
    SKIP 使用skip进行跳过
    IDHACK 针对_id进行查询
    SHARDING_FILTER 通过mongos对分片数据进行查询
    COUNT 利用db.coll.explain().count()之类进行count运算
    COUNTSCAN count不使用Index进行count时的stage返回
    COUNT_SCAN count使用了Index进行count时的stage返回
    SUBPLA 未使用到索引的$or查询的stage返回
    TEXT 使用全文索引进行查询时候的stage返回
    PROJECTION 限定返回字段时候stage的返回

    1. > db.getCollection("stepsDetail").find({"ssoid" : "670274649","modifiedTime" : NumberLong(1619671871306) } ).explain("executionStats")
    2. "executionStats" : {
    3. "nReturned" : 27,//查询的返回条数
    4. "executionTimeMillis" : 1,//整体执行时间
    5. "totalKeysExamined" : 27,//索引扫描次数
    6. "totalDocsExamined" : 27,//document扫描次数
    7. "executionStages" : {
    8. "stage" : "SINGLE_SHARD",
    9. "nReturned" : 27,//返回27条数据
    10. "executionTimeMillis" : 1,//该查询根据index去检索document获取27条具体数据的时间
    11. "totalKeysExamined" : 27,//索引扫描次数
    12. "totalDocsExamined" : 27,//document扫描次数
    13. "totalChildMillis" : NumberLong(1),
    14. "shards" : [
    15. {
    16. "shardName" : "sport-health_oXHqoVcC_shard_2",
    17. "executionSuccess" : true,
    18. "executionStages" : {
    19. "stage" : "FETCH",
    20. "nReturned" : 27,
    21. "executionTimeMillisEstimate" : 0,
    22. "works" : 29,
    23. "advanced" : 27,
    24. "needTime" : 0,
    25. "needYield" : 0,
    26. "saveState" : 0,
    27. "restoreState" : 0,
    28. "isEOF" : 1,
    29. "invalidates" : 0,
    30. "docsExamined" : 27,
    31. "alreadyHasObj" : 0,
    32. "inputStage" : {
    33. "stage" : "IXSCAN", //扫描方式
    34. "nReturned" : 27, //查询结果数量
    35. "executionTimeMillisEstimate" : 0, //预估耗时
    36. "works" : 28, //工作单元数,一个查询会分解成小的工作单元
    37. "advanced" : 27, //优先返回的结果数
    38. "needTime" : 0,
    39. "needYield" : 0,
    40. "saveState" : 0,
    41. "restoreState" : 0,
    42. "isEOF" : 1,
    43. "invalidates" : 0,
    44. "keyPattern" : { //索引
    45. "ssoid" : 1,
    46. "modifiedTime" : -1
    47. },
    48. "indexName" : "ssoid_1_modifiedTime_-1",
    49. "isMultiKey" : false,
    50. "multiKeyPaths" : {
    51. "ssoid" : [ ],
    52. "modifiedTime" : [ ]
    53. },
    54. "isUnique" : false,
    55. "isSparse" : false,
    56. "isPartial" : false,
    57. "indexVersion" : 2,
    58. "direction" : "forward",
    59. "indexBounds" : {
    60. "ssoid" : [
    61. "[\"670274649\", \"670274649\"]"
    62. ],
    63. "modifiedTime" : [
    64. "[1619671871306, 1619671871306]"
    65. ]
    66. },
    67. "keysExamined" : 27,
    68. "seeks" : 1,
    69. "dupsTested" : 0,
    70. "dupsDropped" : 0,
    71. "seenInvalidated" : 0
    72. }
    73. }
    74. }
    75. ]
    76. }
    77. }