幽灵公主 發表於 2023-8-11 15:55:00

MongoDB索引操作和执行计划Explain()详解

<p><strong>主要是讲下Mongodb的索引的查看、创建、删除、类型说明,还有就是Explain执行计划的解释说明。&nbsp;</strong></p>
<p>&nbsp;</p>
<p><strong>可以转载,但请注明出处。</strong>&nbsp;&nbsp;</p>
<p>之前自己写的SpringBoot整合MongoDB的聚合查询操作,感兴趣的可以点击查阅。</p>
<p>https://www.cnblogs.com/zaoyu/p/springboot-mongodb.html</p>
<p>数组相关的操作</p>
<p>https://www.cnblogs.com/zaoyu/p/mongodb_array_operator.html</p>
<p>&nbsp;</p>
<h2 class="md-end-block md-heading"><span class="md-pair-s">一、索引操作</span></h2>
<p class="md-end-block md-p md-focus"><span class="md-plain md-expand">说明,下面的内容举例时,以"dailyTrip"collection为例。 字段内容如下:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
    </span>"_id" : ObjectId("63ec5a971ddbe429cbeeffe3"),<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> object id</span>
    "car_type" : "Gett",<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string</span>
    "date" : ISODate("2016-04-01T00:00:00.000+0000"),<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">ISODate</span>
    "trips" : 0.0,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number</span>
    "monthly" : "NA", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string</span>
    "parent_type" : "Ride-hailing apps", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string</span>
    "monthly_is_estimated" : <span style="color: rgba(0, 0, 255, 1)">true</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> boolean</span>
    "geo" : {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> object </span>
      "$concat" : [<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> array </span>
            "$parent_type"<span style="color: rgba(0, 0, 0, 1)">,
            </span>"$grouping"<span style="color: rgba(0, 0, 0, 1)">
      ]
    }
}</span></pre>
</div>
<p>执行看看有5.17万条数据</p>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811154814601-728006663.png"></p>
<h3 class="md-end-block md-heading md-focus"><span class="md-plain md-expand">1. 索引类型</span></h3>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">单列索引: 在一个字段上创建的索引。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">复合索引:由多个字段组合一起创建的索引。使用的时候要注意最左前缀原则,避免索引无法命中(失效)。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">文本索引(全文索引)和空间索引(GEO索引),不常用,这里不讲,具体自行网上查询。</span></p>
</li>
</ul>
<p>&nbsp;</p>
<h3 class="md-end-block md-heading"><span class="md-plain">2. 查看</span></h3>
<p class="md-end-block md-p"><strong><span class="md-plain">语法: </span></strong></p>
<div class="cnblogs_code">
<pre>db.Collection.getIndexs(); </pre>
</div>
<p><strong>返回内容说明:</strong></p>
<div class="cnblogs_code">
<pre>[<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回一个数组,内容是所有索引</span>
<span style="color: rgba(0, 0, 0, 1)">    {
      </span>"v" : 2.0,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 索引版本,可忽略</span>
      "key" : {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 索引加在哪个字段,以及排序</span>
            "_id" : 1.0<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> _id 是字段, 1.0是正序(升序), -1.0是倒序(倒序)</span>
<span style="color: rgba(0, 0, 0, 1)">      },
      </span>"name" : "_id_"<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 索引名,如果添加的时候没有指定,Mongo会自动生成。 </span>
<span style="color: rgba(0, 0, 0, 1)">    }
]</span></pre>
</div>
<p><strong>举例:</strong></p>
<p>可以看到返回一个name为 _id_的索引。 作用于 _id上, 升序排列。</p>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811154926606-1549821035.png"></p>
<h3 class="md-end-block md-heading"><span class="md-plain md-expand">3. 创建</span></h3>
<p class="md-end-block md-p md-focus"><strong><span class="md-plain">语法:</span></strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.collection.createIndex(keys, options)

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 组合索引 </span>
db.collection.createIndex( { &lt;field1&gt;: &lt;type&gt;, &lt;field2&gt;: &lt;type2&gt;, ... } )<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 其中 &lt;fieldN&gt;是字段名 &lt;typeN&gt;是排序</span>
<span style="color: rgba(0, 0, 0, 1)">
注意:</span>3.0.0 版本之前创建索引方法为 db.collection.ensureIndex()。 5.0之后ensureIndex() 已被移除。</pre>
</div>
<p><strong><span class="md-plain">举例:</span></strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建单字段索引</span>
db.dailyTrip.createIndex({"car_type":1<span style="color: rgba(0, 0, 0, 1)">});

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回结果 </span>
<span style="color: rgba(0, 0, 0, 1)">{
    </span>"numIndexesBefore" : 1.0,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 新建索引前的索引数</span>
    "numIndexesAfter" : 2.0,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 新建索引后的索引数</span>
    "createdCollectionAutomatically" : <span style="color: rgba(0, 0, 255, 1)">false</span>,   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 一般情况下,如果该集合存在,这里就是返回false。如果指定的集合不存在,MongoDB 默认情况下会自动创建该集合,并在该集合上创建索引,此时返回true。</span>
    "ok" : 1.0<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建结果 1.0则是成功。返回0则说明报错了。</span>
<span style="color: rgba(0, 0, 0, 1)">}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果创建的字段的索引已经存在,则返回如下</span>
<span style="color: rgba(0, 0, 0, 1)">{
    </span>"numIndexesBefore" : 2.0<span style="color: rgba(0, 0, 0, 1)">,
    </span>"numIndexesAfter" : 2.0<span style="color: rgba(0, 0, 0, 1)">,
    </span>"note" : "all indexes already exist", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 提示已经存在</span>
    "ok" : 1.0<span style="color: rgba(0, 0, 0, 1)">
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建复合索引</span>
db.dailyTrip.createIndex({"parent_type":1, "car_type":1<span style="color: rgba(0, 0, 0, 1)">})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 也可以指定自定义索引名</span>
db.dailyTrip.createIndex({"parent_type":1, "car_type":1}, { name: "inx_parantType_carType" })<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里自己试验</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 来自官方文档 https://www.mongodb.com/docs/manual/reference/command/createIndexes/ </span></pre>
</div>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811155101886-1211085675.png"></p>
<p>&nbsp;</p>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811155107415-863878336.png"></p>
<p>&nbsp;创建完毕后,再次查看当前索引情况</p>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811155114157-795194901.png"></p>
<p>&nbsp;</p>
<h3 class="md-end-block md-heading"><span class="md-plain">4. 删除</span></h3>
<p class="md-end-block md-p"><span class="md-plain">语法:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">删除指定集合中所有索引:
db.collection.dropIndexes();
删除指定集合中的具体索引:
db.collection.dropIndex(</span>"索引名称");</pre>
</div>
<p><strong><span class="md-plain">举例:</span></strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 删除指定索引</span>
db.dailyTrip.dropIndex("car_type_1"<span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回结果</span>
<span style="color: rgba(0, 0, 0, 1)">{
    </span>"nIndexesWas" : 3.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 指示在删除索引之前集合中存在的索引数量。</span>
    "ok" : 1.0<span style="color: rgba(0, 0, 0, 1)">
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 删除所有,自行尝试。 注意, 主键_id的索引是不会也不能被删除的。 </span>
db.collection.dropIndexes();</pre>
</div>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811155226504-191285753.png"></p>
<p>&nbsp;</p>
<h3 class="md-end-block md-heading"><span class="md-plain">5. 修改</span></h3>
<p class="md-end-block md-p"><span class="md-plain">无法直接修改,如果需要调整索引字段、名称、组合索引的顺序,需要先删除原来索引,再新建索引。 </span></p>
<h3 class="md-end-block md-heading"><span class="md-plain">6. 索引使用原则</span></h3>
<ol class="ol-list">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">选择经常被查询的字段来创建索引。那些在查询条件、排序和聚合操作中频繁出现的字段是最佳选择。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">选择合适的、常用作查询条件的字段,综合判断是否可以使用复合索引,如果可以优先复合索引。 比如多数情况是按照字段A、B、C或者A、B条件去查询,那么可以优先考虑基于字段A、B、C创建复合索引。 使用复合索引来覆盖多个查询条件,以减少索引的数量。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">尽量使用索引覆盖,和MySQL中的索引覆盖是类似的。 覆盖索引是指索引包含了查询所需的字段,从而避免了查询需要访问实际文档。这可以提高查询性能,减少IO操作。 其实这里和上面的复合索引是相关的。 </span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">其他的还有包括使用Explain去查看执行计划、定期监控性能、删除冗余无用的索引之类的,不一而足。 上面是基于实际开发经验得出的常用手段原则。</span></p>
<p class="md-end-block md-p">&nbsp;</p>
</li>
</ol>
<h3 class="md-end-block md-heading"><span class="md-plain">7. 索引失效的情况</span></h3>
<ol class="ol-list">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s "><strong>查询条件不满足索引前缀:</strong><span class="md-plain"> 例如,复合索引是 <span class="md-pair-s"><code>{ a: 1, b: 1 }</code><span class="md-plain">,而查询条件只包含 <span class="md-pair-s"><code>{ b: 1 }</code><span class="md-plain">,则该复合索引将无法被使用。</span></span></span></span></span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s "><strong>数据类型不匹配:</strong><span class="md-plain"> 如果查询条件中的数据类型与索引字段的数据类型不匹配,索引可能无法被使用。例如,如果索引字段是数字类型,而查询条件中使用了字符串类型的值,索引将无法被使用。</span></span></p>
<p class="md-end-block md-p"><span class="md-plain">// 类似Mysql中的隐式转换会使索引失效。 </span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s "><strong>索引选择性低:</strong><span class="md-plain"> 索引的选择性是指索引中不同值的唯一性程度。如果索引的选择性很低,即索引中的值几乎都相同,那么使用该索引可能不会带来明显的性能提升。 </span></span></p>
<p class="md-end-block md-p"><span class="md-plain">// 这里其实是说索引列的值的区分度,如果重复度过高,那么使用索引的性能可能不如不用,索引底层优化器可能不选择使用索引。假如字段gender只有2个值,male和female,其中一半数据是male,另一半是female,此时用gender索引,还不如不用。 </span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s "><strong>使用不支持的操作符:</strong><span class="md-plain"> 某些查询操作符可能无法使用索引。例如,正则表达式查询、模糊查询(如 <span class="md-pair-s"><code>$text</code><span class="md-plain"> 操作符)等可能无法充分利用索引。</span></span></span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s "><strong>数据量较小:</strong><span class="md-plain"> 当集合中的数据量较小时,MongoDB 可能会选择全表扫描而不使用索引,因为全表扫描可能更快。</span></span></p>
<p class="md-end-block md-p"><span class="md-plain">// 类似mysql中,一般建议小于1000条就不加索引,因为索引有额外开销。 </span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s "><strong>索引过期或损坏:</strong><span class="md-plain"> 如果索引过期或损坏,MongoDB 将无法使用该索引。</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s"><strong>索引被禁用:</strong><span class="md-plain"> 如果在查询时禁用了索引,或者索引的存储引擎不支持该查询,索引将无法被使用。</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s"><strong>索引尺寸过大:</strong><span class="md-plain"> 如果索引的尺寸超过了 MongoDB 的限制,该索引可能无法被使用。</span></span></p>
</li>
</ol>
<p class="md-end-block md-p"><span class="md-plain">使用 <span class="md-pair-s"><code>explain()</code><span class="md-plain"> 方法可以查看查询计划和索引使用情况,帮助识别索引失效的原因,并进行相应的优化。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">接下来对Explain方法做说明解释。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2 class="md-end-block md-heading"><span class="md-plain">二、执行计划 Explain()</span></h2>
<h3 class="md-end-block md-heading md-focus"><span class="md-plain">1. <span class="md-pair-s md-expand">什么是Explain()执行计划?</span></span></h3>
<ol class="ol-list">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s"><code>explain()</code><span class="md-plain"> 是一个用于查询解释和性能分析的方法(函数)。</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">可以在<span class="md-pair-s"><code>find()</code><span class="md-plain">、<span class="md-pair-s"><code>aggregate()</code><span class="md-plain"> 和 <span class="md-pair-s"><code>count()</code><span class="md-plain"> 等查询操作的结果上调用 <span class="md-pair-s"><code>explain()</code><span class="md-plain"> 方法。</span></span></span></span></span></span></span></span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">其作用:</span></p>
<ol class="ol-list">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">有助于了解查询的执行计划、索引使用情况以及查询性能的相关指标。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">调用该方法后。MongoDB 会返回一条包含查询执行计划的文档(结果)(具体说明如下),其中包含了查询优化器的决策、索引使用情况、扫描文档数量等信息。通过分析 <span class="md-pair-s"><code>explain()</code><span class="md-plain"> 返回的执行计划,可以确定是否使用了适当的索引,是否存在潜在的性能问题,并根据需要进行索引优化、查询重写等操作,以提高查询性能。</span></span></span></p>
</li>
</ol></li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">执行计划的返回结果:</span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s"><code>queryPlanner</code><span class="md-plain">:查询优化器的决策和统计信息。</span></span></p>
</li>
</ul>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s"><code>winningPlan</code><span class="md-plain">:优化器选择的最佳执行计划。</span></span></p>
</li>
</ul>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s"><code>executionStats</code><span class="md-plain">:执行计划的统计信息,如扫描的文档数量、查询时间等。</span></span></p>
</li>
</ul>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-pair-s"><code>serverInfo</code><span class="md-plain">:MongoDB 服务器的信息。</span></span></p>
</li>
</ul>
</li>
</ol>
<p class="md-end-block md-p"><span class="md-plain">注意:explain()` 的输出非常详细,包含了大量的信息。因此,它在调试和优化查询时非常有用,但在生产环境中不应该频繁地使用,以避免对性能产生负面影响。</span></p>
<p class="md-end-block md-p"><span class="md-pair-s "><strong>官方文档:</strong></span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">explain的详细说明 <span class="md-link md-pair-s">https://www.mongodb.com/docs/v5.0/reference/command/explain/</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">explain的返回结果的详细说明 <span class="md-link md-pair-s">https://www.mongodb.com/docs/v5.0/reference/explain-results/</span></span></p>
</li>
</ul>
<h3 class="md-end-block md-heading md-focus"><span class="md-plain md-expand">2. Explain的语法和使用</span></h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">语法
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 普通的语句,直接在语句后面加上explain,也可以挪到find的前面。</span>
db.collection.find({}).explain(&lt;optional verbosity mode&gt;<span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对聚合pipeline的执行计划分析,explain放前面 </span>
db.collection.explain(&lt;optional verbosity mode&gt;<span style="color: rgba(0, 0, 0, 1)">).aggregate([]);

</span>&lt;optional verbosity mode&gt;<span style="color: rgba(0, 0, 0, 1)"> 是可选的输出模式。
如果什么都不写,比如db.collection.find({</span>"name"”":"onepiece"}).explain();那么mongo会走默认模式 "queryPlanner"<span style="color: rgba(0, 0, 0, 1)">。
如果要指定模式,则直接加上,比如db.collection.find({</span>"name"”":"onepiece"}).explain("executionStats")</pre>
</div>
<p class="md-end-block md-p"><span class="md-plain">explain有三种模式:</span></p>
<ol class="ol-list">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">queryPlanner (默认) : 只列出所有可能执行的方案,不会执行实际的语句,显示已经胜出的方案winningPlan(最佳查询计划)。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">executionStats : 只执行winningPlan方案,并输出结果。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">allPlansExecution :执行所有的方案,并输出结果。</span></p>
</li>
</ol>
<p class="md-end-block md-p md-focus"><span class="md-plain md-expand">关于explain的参数可以参考官网: <span class="md-link md-pair-s">https://www.mongodb.com/docs/v5.0/reference/method/cursor.explain/#std-label-explain-cursor-method-verbosity</span></span></p>
<p class="md-end-block md-p">&nbsp;</p>
<h3 class="md-end-block md-heading"><span class="md-plain">3. 三种模式下的说明和结果解释</span></h3>
<h4 class="md-end-block md-heading"><span class="md-plain">3.1 queryPlanner 模式</span></h4>
<p class="md-end-block md-p"><span class="md-plain">运行查询优化器对当前的查询进行评估并选择一个最佳的查询计划,不执行实际语句。</span></p>
<p class="md-end-block md-p">&nbsp;</p>
<p class="md-end-block md-p"><span class="md-plain">下面三种模式均以这个查询语句为例:</span></p>
<div class="cnblogs_code">
<pre>db.getCollection("dailyTrip").explain().find({"parent_type":"Ride-hailing apps"}, { _id:0});</pre>
</div>
<p>下面是一个执行的返回结果,我把详细内容先收起,可以看到返回的字段有哪些。</p>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811155723179-894023109.png"></p>
<p>&nbsp;</p>
<p>具体解释</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
    </span>"explainVersion" : "1",<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 执行计划的版本,可以忽略 </span>
    "queryPlanner" : {   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">queryPlanner,就是执行计划。 这部分重点看</span>
      "namespace" : "test.dailyTrip",<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 就是collection和所在db</span>
      "indexFilterSet" : <span style="color: rgba(0, 0, 255, 1)">false</span>,   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 是否设置了索引过滤器集合,Filter决定了查询优化器对于某个查询将如何使用索引</span>
      "parsedQuery" : {    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 经过解析后的query内容。</span>
            "parent_type"<span style="color: rgba(0, 0, 0, 1)"> : {
                </span>"$eq" : "Ride-hailing apps"<span style="color: rgba(0, 0, 0, 1)">
            }
      },
      </span>"queryHash" : "8B8C334A",<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询的哈希值,</span>
      "planCacheKey" : "F910A33F", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询执行计划的缓存键</span>
      "maxIndexedOrSolutionsReached" : <span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 是否已达到最大索引【或】解决方案的限制。跳过</span>
      "maxIndexedAndSolutionsReached" : <span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 表示是否已达到最大索引【和】解决方案的限制。 跳过</span>
      "maxScansToExplodeReached" : <span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 是否已达到最大扫描数的限制。 跳过</span>
      "winningPlan" : {   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这个很关键,这里是最后底层选择的执行计划。   </span>
            "stage" : "PROJECTION_DEFAULT",<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> stage 是指步骤 可以由stage名称看到具体做了什么。 projection是应用投影操作,选择所需的字段</span>
            "transformBy" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 具体投影内容跳过</span>
                "_id" : 0.0<span style="color: rgba(0, 0, 0, 1)">
            },
            </span>"inputStage" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 执行阶段的子阶段,这里是一个FETCH的子过程</span>
                "stage" : "FETCH",   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> FETCH是 从索引中获取文档数据。</span>
                "inputStage" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 其中一个阶段,具体操作。 这里面的东西是重点要看的。 </span>
                  "stage" : "IXSCAN", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里是说使用索引进行扫描,通常表示优化的查询。</span>
                  "keyPattern" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 表示下面的索引字段的排列方式,1.0正序,-1.0倒序。</span>
                        "parent_type" : 1.0<span style="color: rgba(0, 0, 0, 1)">,
                        </span>"car_type" : 1.0<span style="color: rgba(0, 0, 0, 1)">
                  },
                  </span>"indexName" : "parent_type_1_car_type_1", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 用到的索引名称</span>
                  "isMultiKey" : <span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 是否为多键索引。 如果为 true,表示索引包含数组值</span>
                  "multiKeyPaths" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果索引是多键索引,这个属性将会包含索引中包含数组值的字段路径。本例中的索引不是多键索引,因此下面的字段为空数组。</span>
                        "parent_type"<span style="color: rgba(0, 0, 0, 1)"> : [
                        ],
                        </span>"car_type"<span style="color: rgba(0, 0, 0, 1)"> : [
                        ]
                  },
                  </span>"isUnique" : <span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 是否为唯一索引</span>
                  "isSparse" : <span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 是否为稀疏索引</span>
                  "isPartial" : <span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 是否为部分索引</span>
                  "indexVersion" : 2.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 索引版本 </span>
                  "direction" : "forward", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 索引的遍历方向</span>
                  "indexBounds" : {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 当前查询具体使用的索引</span>
                        "parent_type"<span style="color: rgba(0, 0, 0, 1)"> : [
                            </span>"[\"Ride-hailing apps\", \"Ride-hailing apps\"]"<span style="color: rgba(0, 0, 0, 1)">
                        ],
                        </span>"car_type"<span style="color: rgba(0, 0, 0, 1)"> : [
                            </span>""<span style="color: rgba(0, 0, 0, 1)">
                        ]
                  }
                }
            }
      },
      </span>"rejectedPlans" : [<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 底层优化器拒绝的计划,没有执行的计划。</span>
<span style="color: rgba(0, 0, 0, 1)">      ]
    },
    </span>"command" : {   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 语句具体涉及到的命令、collection、DB</span>
      "find" : "dailyTrip",<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 表名 从哪个collection中查找</span>
      "filter" : {   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 哪个阶段,这里就是过滤</span>
            "parent_type" : "Ride-hailing apps"<span style="color: rgba(0, 0, 0, 1)">
      },
      </span>"projection" : {   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 投影 控制要返回的字段 </span>
            "_id" : 0.0<span style="color: rgba(0, 0, 0, 1)">
      },
      </span>"$db" : "test"   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 库</span>
<span style="color: rgba(0, 0, 0, 1)">    },
    </span>"serverInfo" : {   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 服务器信息   </span>
      "host" : "onepiece-pc",<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> mongo的示例主机名称</span>
      "port" : 27017.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">端口</span>
      "version" : "5.0.9", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> mongodb的版本</span>
      "gitVersion" : "6f7dae919422dcd7*****************1ad00e6"<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里是git版本,这里无关紧要,我脱敏了。 </span>
<span style="color: rgba(0, 0, 0, 1)">    },
    </span>"serverParameters" : {   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 服务器的参数,各种缓存大小、最大阈值设置,暂时和我们这里说的内容无关,跳过。</span>
      "internalQueryFacetBufferSizeBytes" : 104857600.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"internalQueryFacetMaxOutputDocSizeBytes" : 104857600.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"internalLookupStageIntermediateDocumentMaxSizeBytes" : 104857600.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"internalDocumentSourceGroupMaxMemoryBytes" : 104857600.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"internalQueryMaxBlockingSortMemoryUsageBytes" : 104857600.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"internalQueryProhibitBlockingMergeOnMongoS" : 0.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"internalQueryMaxAddToSetBytes" : 104857600.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"internalDocumentSourceSetWindowFieldsMaxMemoryBytes" : 104857600.0<span style="color: rgba(0, 0, 0, 1)">
    },
    </span>"ok" : 1.0<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<h4 class="md-end-block md-heading"><span class="md-plain">3.2 executionStats模式</span></h4>
<div class="cnblogs_code">
<pre>db.getCollection("dailyTrip").find({"parent_type":"Ride-hailing apps"}, { _id:0}).explain("executionStats");</pre>
</div>
<p>运行查询优化器对当前的查询进行评估并选择一个最佳的查询计划进行执行,在执行完毕后返回这个最佳执行计划执行完成时的相关统计信息。</p>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811155804870-1717072632.png"></p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
    </span>"explainVersion" : "1"<span style="color: rgba(0, 0, 0, 1)">,
    </span>"queryPlanner"<span style="color: rgba(0, 0, 0, 1)"> : {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
      "parsedQuery"<span style="color: rgba(0, 0, 0, 1)"> : {
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">      },
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
      "winningPlan"<span style="color: rgba(0, 0, 0, 1)"> : {
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">      }
      </span>"rejectedPlans"<span style="color: rgba(0, 0, 0, 1)"> : [
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">      ]
    },
    </span>"executionStats" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 重点留意这里面的内容</span>
      "executionSuccess" : <span style="color: rgba(0, 0, 255, 1)">true</span>,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 执行结果</span>
      "nReturned" : 23010.0,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回的文档数</span>
      "executionTimeMillis" : 70.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 执行耗时 ms</span>
      "totalKeysExamined" : 23010.0,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 扫描了的索引总数</span>
      "totalDocsExamined" : 23010.0,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 总的扫描文档数</span>
      "executionStages" : {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 执行stage 里面会有具体每个stage的详细</span>
            "stage" : "PROJECTION_DEFAULT",<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阶段类型</span>
            "nReturned" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
            </span>"executionTimeMillisEstimate" : 10.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 预估执行时间ms</span>
            "works" : 23011.0,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阶段中扫描任务数</span>
            "advanced" : 23010.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阶段中向上提交数量</span>
            "needTime" : 0.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阶段中定位索引位置所需次数</span>
            "needYield" : 0.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阶段中获取锁等待时间</span>
            "saveState" : 23.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> :表示在查询执行过程中,保存中间状态所花费的时间 ms</span>
            "restoreState" : 23.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 表示在查询执行过程中,恢复之前保存的中间状态所花费的时间 ms</span>
            "isEOF" : 1.0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阶段中是否到达流的结束位,对于limit限制符的查询可能为0</span>
            "transformBy" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 表示查询计划是否使用了投影操作来转换结果 </span>
                "_id" : 0.0<span style="color: rgba(0, 0, 0, 1)">
            },
            </span>"inputStage" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 执行阶段的子阶段,这里是一个fetch的子过程</span>
                "stage" : "FETCH", <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 内容差不多 </span>
                "nReturned" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"executionTimeMillisEstimate" : 4.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"works" : 23011.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"advanced" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"needTime" : 0.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"needYield" : 0.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"saveState" : 23.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"restoreState" : 23.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"isEOF" : 1.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"docsExamined" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"alreadyHasObj" : 0.0<span style="color: rgba(0, 0, 0, 1)">,
                </span>"inputStage" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">子阶段,ixscan子过程</span>
                  "stage" : "IXSCAN"<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"nReturned" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"executionTimeMillisEstimate" : 4.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"works" : 23011.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"advanced" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"needTime" : 0.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"needYield" : 0.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"saveState" : 23.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"restoreState" : 23.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"isEOF" : 1.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"keyPattern"<span style="color: rgba(0, 0, 0, 1)"> : {
                        </span>"parent_type" : 1.0<span style="color: rgba(0, 0, 0, 1)">,
                        </span>"car_type" : 1.0<span style="color: rgba(0, 0, 0, 1)">
                  },
                  </span>"indexName" : "parent_type_1_car_type_1"<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"isMultiKey" : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                  </span>"multiKeyPaths"<span style="color: rgba(0, 0, 0, 1)"> : {
                        </span>"parent_type"<span style="color: rgba(0, 0, 0, 1)"> : [

                        ],
                        </span>"car_type"<span style="color: rgba(0, 0, 0, 1)"> : [

                        ]
                  },
                  </span>"isUnique" : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                  </span>"isSparse" : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                  </span>"isPartial" : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                  </span>"indexVersion" : 2.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"direction" : "forward"<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"indexBounds"<span style="color: rgba(0, 0, 0, 1)"> : {
                        </span>"parent_type"<span style="color: rgba(0, 0, 0, 1)"> : [
                            </span>"[\"Ride-hailing apps\", \"Ride-hailing apps\"]"<span style="color: rgba(0, 0, 0, 1)">
                        ],
                        </span>"car_type"<span style="color: rgba(0, 0, 0, 1)"> : [
                            </span>""<span style="color: rgba(0, 0, 0, 1)">
                        ]
                  },
                  </span>"keysExamined" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"seeks" : 1.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"dupsTested" : 0.0<span style="color: rgba(0, 0, 0, 1)">,
                  </span>"dupsDropped" : 0.0<span style="color: rgba(0, 0, 0, 1)">
                }
            }
      }
    },
    </span>"command" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">    },
    </span>"serverInfo" : { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">    },
    </span>"serverParameters" : {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">    },
    </span>"ok" : 1.0<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<h4 class="md-end-block md-heading"><span class="md-plain">3.3 allPlansExecution模式</span></h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 调用explain("allPlansExecution"), allPlansExecution 模式,执行所有的方案,并输出结果。</span>
db.getCollection("dailyTrip").find({"parent_type":"Ride-hailing apps"}, { _id:0}).explain("allPlansExecution");</pre>
</div>
<p class="md-end-block md-p"><span class="md-plain">allPlansExecution相比executionStats,其他的备选执行计划也会去执行,并统计结果出来。 会存放在 executionStats中。 </span></p>
<p class="md-end-block md-p"><span class="md-plain">即按照最佳的执行计划执行以及列出统计信息, 如果有多个查询计划,还会列出这些非最佳执行计划部分的统计信息。</span></p>
<p><img src="https://img2023.cnblogs.com/blog/3057271/202308/3057271-20230811155832946-419014039.png"></p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
    </span>"explainVersion" : "1"<span style="color: rgba(0, 0, 0, 1)">,
    </span>"queryPlanner"<span style="color: rgba(0, 0, 0, 1)"> : {
      </span>"namespace" : "test.dailyTrip"<span style="color: rgba(0, 0, 0, 1)">,
      </span>"indexFilterSet" : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
      </span>"parsedQuery"<span style="color: rgba(0, 0, 0, 1)"> : {
            </span>"parent_type"<span style="color: rgba(0, 0, 0, 1)"> : {
                </span>"$eq" : "Ride-hailing apps"<span style="color: rgba(0, 0, 0, 1)">
            }
      },
      </span>"maxIndexedOrSolutionsReached" : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
      </span>"maxIndexedAndSolutionsReached" : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
      </span>"maxScansToExplodeReached" : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
      </span>"winningPlan"<span style="color: rgba(0, 0, 0, 1)"> : {
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">      },
      </span>"rejectedPlans"<span style="color: rgba(0, 0, 0, 1)"> : [
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">      ]
    },
    </span>"executionStats"<span style="color: rgba(0, 0, 0, 1)"> : {
      </span>"executionSuccess" : <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
      </span>"nReturned" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"executionTimeMillis" : 68.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"totalKeysExamined" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"totalDocsExamined" : 23010.0<span style="color: rgba(0, 0, 0, 1)">,
      </span>"executionStages"<span style="color: rgba(0, 0, 0, 1)"> : {
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里的executionStage和2.2的executionStats中的executionstages一样,参考那里。 </span>
<span style="color: rgba(0, 0, 0, 1)">      },
      </span>"allPlansExecution" : [<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 重点:allPlansExecution 如果有其他执行计划,那么会在这里把执行统计结果放出来。   </span>
<span style="color: rgba(0, 0, 0, 1)">      ]
    },
    </span>"command" : {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">    },
    </span>"serverInfo" : {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">    },
    </span>"serverParameters" : {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... 同上,省略。</span>
<span style="color: rgba(0, 0, 0, 1)">    },
    </span>"ok" : 1.0<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<h4 class="md-end-block md-heading"><span class="md-plain">Stage参数值</span></h4>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">COLLSCAN:全表扫描</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">IXSCAN:索引扫描</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">FETCH:根据索引去检索指定document</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SHARD_MERGE:将各个分片返回数据进行merge</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SORT:表明在内存中进行了排序</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LIMIT:使用limit限制返回数</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SKIP:使用skip进行跳过</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">IDHACK:针对_id进行查询</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SHARDING_FILTER:通过mongos对分片数据进行查询 ---服务器是分片的才有。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">COUNT:利用db.coll.explain().count()之类进行count运算</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">COUNTSCAN: count不使用Index进行count时的stage返回</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">COUNT_SCAN: count使用了Index进行count时的stage返回</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SUBPLA:未使用到索引的$or查询的stage返回</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">TEXT:使用全文索引进行查询时候的stage返回</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">PROJECTION:限定返回字段时候stage的返回</span></p>
</li>
</ul>
<h4 class="md-end-block md-heading"><span class="md-plain">参考文档</span></h4>
<p class="md-end-block md-p"><span class="md-link md-pair-s">https://www.cnblogs.com/littleatp/p/8419678.html</span></p>
<p class="md-end-block md-p">&nbsp;</p>
<h3 class="md-end-block md-heading"><span class="md-plain">4. 查询优化思路</span></h3>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">尽量使用索引。 举例,比如通过上面的执行计划发现某个作为查询条件的字段,没有用上索引,且通过索引可以极大提高性能,那么可以考虑对该字段增加索引。 </span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">扫描文档数越小越好。举例,比如上面的执行计划中,某个阶段返回的扫描文档数量极大,那么可以考虑优化语句,比如调整语句顺序,先过滤再处理;或者对查询条件字段增加索引。</span></p>
</li>
</ul>
<p>&nbsp;</p>
<p>完。</p>
<p>感谢查阅,希望对你有帮助,点个赞再走呗~</p><br><br>
来源:https://www.cnblogs.com/zaoyu/p/17623197.html
頁: [1]
查看完整版本: MongoDB索引操作和执行计划Explain()详解