山崖 發表於 2019-6-11 19:10:00

MongoDB查询及索引优化

<p><span data-wiz-span="data-wiz-span">MongoDB查询与游标详解</span></p>
<p>&nbsp; &nbsp; 游标定义:是一种能从数据记录的结果集中每次提取一条记录的机制</p>
<p>&nbsp; &nbsp;&nbsp;游标作用:可以随意控制最终结果集的返回,如限制返回数量、跳过记录、按字段排序、设置游标超时等。</p>
<p>&nbsp; &nbsp; MongoDB中的游标</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 对于MongoDB每个查询默认返回一个游标,游标包括定义、打开、读取、关闭。</p>
<p>&nbsp; &nbsp; MongoDB游标生命周期</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 游标声明 var cursor=db.collection.find({xxx}) &nbsp; (MongoDB单条记录的最大大小是16M)</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 打开游标 cursor.hasNext() &nbsp;游标是否已经迭代到了最后(正在访问数据库)</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 读取游标 cursor.Next() &nbsp; 获取游标下一个文档(正在访问数据库)</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 关闭游标 cursor.close() &nbsp;通常迭代完毕会自动关闭,也可以显示关闭</p>
<p>&nbsp; &nbsp; MongoDB游标常见方法<br>&nbsp; &nbsp; &nbsp; &nbsp; cursor.batchSize(size) &nbsp; 指定游标从数据库每次批量获取文档的个数限制</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.count() &nbsp; &nbsp; &nbsp; &nbsp;统计游标中记录总数</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.explain(verbosity) &nbsp; 输出对应的执行计划</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.forEach() &nbsp; &nbsp;采用js函数forEach对每一行进行迭代</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.hasNext() &nbsp; &nbsp;判断游标记录是否已经迭代完毕</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.hint(index) &nbsp; &nbsp;认为强制指定优化器的索引选择</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.limit() &nbsp; &nbsp; 指定游标返回的最大记录数</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.maxTimeMS(time) &nbsp; &nbsp;指定游标两次getmore间隔的最大处理时间(毫秒)推荐</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.next() &nbsp; &nbsp;返回游标下一条记录</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.noCursorTimeout() &nbsp; &nbsp;强制不自动对空闲游标进行超时时间计算(默认10分钟)慎用</p>
<p>&nbsp; &nbsp;&nbsp;MongoDB shell下游标示例 1</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;隐式游标</p>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;db.t2.find() // 默认迭代20次,其后采用it手动迭代</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DBQuery.shellBatchSize = 10 &nbsp; &nbsp;调整游标每批次返回的记录数</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;显示游标</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; var cursor = db.test.find() &nbsp;游标定义,此时不会正在访问数据库</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while (cursor.hasNext()){</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;printjson(cursor.next())}</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 或</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.test.find().forEach(function(e){printjson(e)}) &nbsp;匿名游标迭代</p>
<p>&nbsp; &nbsp;&nbsp;MongoDB shell下游标示例 2</p>
<blockquote>
<p>游标方法hint()</p>
<p>db.person.find({age:1,name:"andy"}).explain()</p>
<p>db.person.find({age:1,name:"andy"}).hint("age_1_name_1").explain()</p>
<p>游标方法maxTimeMS(time)</p>
<p>&nbsp;DBQuery.shellBatchSize = 100000</p>
<p>db.t2.find({type:3}).maxTimeMS(1)</p>
<p>修改游标超时时间</p>







</blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.adminCommand( { setParameter: 1, cursorTimeoutMillis: 300000 } )&nbsp; &nbsp;</p>
<p>&nbsp; &nbsp;&nbsp;MongoDB游标最佳实践</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;游标超时时间与batchsize大小需计算好,避免在getmore时发生不必要的超时</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;如果业务只需要第一批迭代则查询时可指定singleBatch:True及时关闭游标</p>
<p>&nbsp; &nbsp;&nbsp;MongoDB游标状态信息</p>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;db.serverStatus().metrics.cursor</p>
<p><span data-wiz-span="data-wiz-span">MongoDB索引原理及优化</span></p>
<div>
<blockquote>
<div>MongoDB索引原理</div>
<div><img src="https://img2018.cnblogs.com/blog/1063516/201906/1063516-20190611190301883-719742270.png">
<p>db.index.find({}).showRecordId()</p>
<p><img src="https://img2018.cnblogs.com/blog/1063516/201906/1063516-20190611190333621-1511494587.png"></p>
<p>&nbsp;</p>





</div>
<div>可以理解为每条记录对应的映射地址</div>





</blockquote>





</div>
<p>
&nbsp; &nbsp;&nbsp;MongoDB索引类型:</p>
<div>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MongoDB提供了对集合任意字段创建索引的全面支持</div>
<div>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; 默认情况下所有普通集合都会自动创建_id唯一性索引</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; 单列索引</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; 多列索引</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; 多键索引</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; 文本索引</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; 2d</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; 2dsphere</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; hash索引</div>
<div>&nbsp;</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 单列索引</div>
<div><img src="https://img2018.cnblogs.com/blog/1063516/201906/1063516-20190611190406411-1449973629.png">
<p>&nbsp;</p>



</div>
<p>&nbsp;</p>
<blockquote>
<blockquote>
<div>&nbsp; &nbsp; db.test.createlndex({socre:1},{background:true,name:"xx_index"})</div>







</blockquote>
<blockquote>
<div>&nbsp; &nbsp; 默认创建索引加库级别排它锁,可指定<span style="color: rgba(255, 0, 0, 1)">background为true</span>避免阻塞,默认索引名词:字段名_1 /_-1</div>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp;&nbsp;使用background:true构建索引过程依然会阻塞(同DB下)db.collection.drop(),repairDatabase等命令</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp;&nbsp;可执行db.currentOp()查看索引构建进度也可使用db.killOp()强制中断索引创建。</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp;&nbsp;当副本集/分片节点索引创建被强制中断后可通过指定indexBuildRetry参数控制节点重启后是否自动重建索引,</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp;&nbsp;同时只有当索引构建完毕后才能被对应的查询语句利用</p>







</blockquote>







</blockquote>
<blockquote>
<blockquote>
<div>&nbsp; &nbsp; 对单列索引而言,升序和降序都能够用到索引</div>







</blockquote>
<blockquote>
<div>&nbsp; &nbsp; db.records.find({score:2})</div>







</blockquote>
<blockquote>
<div>&nbsp; &nbsp; db.records.find({ score : {$gt :10}})</div>

</blockquote>

</blockquote>
<p>&nbsp;</p>
<p>&nbsp;</p>
<blockquote>
<blockquote>
<p>嵌套单列索引:</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; db.test.find()</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; {"_id": xxxxxxx,"score:100", "location":{contry:"china",city:beijing}}</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; 在嵌入式文档上创建索引</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp;db.test.createIndex({"location":1},{background:true})</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 如下查询会被用到</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.test.find({location:{contry:"china",city:"beijing"}})</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; 在嵌入式字段上创建索引</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp;db.test.createIndex({"location.city":1},{background:true})</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 如下查询会被用到</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.test.find({"location.city":"beijing"})</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.test.find({"location.contry":"chna","location.city":"beijing"})</p>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: rgba(255, 0, 0, 1)">在嵌入式文档上执行相应匹配命令时,字段顺序和嵌入式文档必须完全匹配</span></p>

</blockquote>

</blockquote>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;多列索引</p>
<blockquote>
<blockquote>
<p>db.test2.createIndex(</p>



</blockquote>
<blockquote>
<p>{"userid" : 1, "score" : -1, " age " :1},{background:true})</p>
<p><img src="https://img2018.cnblogs.com/blog/1063516/201906/1063516-20190611190501296-1200797221.png"></p>
<p>索引排序可以简记为:单列索引正反向排序都不受影响,多列索引则是乘以(-1)的排序可以使用相同的索引,即1,1和-1,-1可以使用相同的索引, -1,1和1,-1可以使用相同的索引</p>


</blockquote>


</blockquote>
<p>&nbsp;</p>
<blockquote>
<blockquote>
<p>最左前缀原则</p>


</blockquote>
<blockquote>
<p>for (var i = 0 ;i&lt;500000;i++){&nbsp; &nbsp; db.test10.insert({userid:Math.round(Math.random()*40000),score:Math.round(Math.random()*100),age:Math.round(Math.random()*125)});}&nbsp;&nbsp;</p>


</blockquote>
<blockquote>
<p>创建索引:db.test10.createindex({"userid":1,"score":-1,"age":1},{background:true})</p>


</blockquote>
<blockquote>
<p>以下查询可以使用到索引</p>


</blockquote>
<blockquote>
<blockquote>
<p>db.test10.find({userid:1,score:83,age:20});&nbsp; &nbsp;</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test10.find({score:83,userid:1});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test10.find({age:20,score:83,userid:1});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test10.find({age:20,userid:1});</p>


</blockquote>


</blockquote>
<blockquote>
<p>以下查询不能使用到索引</p>


</blockquote>
<blockquote>
<blockquote>
<p>db.test10.find({score:83,age:20});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test10.find({score:83});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test10.find({age:20});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test10.find({age:20,score:83});</p>


</blockquote>


</blockquote>
<blockquote>
<p>强制索引</p>


</blockquote>
<blockquote>
<p>db.test.find({userid:28440,score:88,age:118}).<span style="color: rgba(255, 44, 33, 1)">hint(</span>"userid_1_score_-1_age_1") ;</p>


</blockquote>
<blockquote>
<p>索引交集</p>
<p>&nbsp; &nbsp;&nbsp;普通索引跟hash索引的组合</p>


</blockquote>
<blockquote>
<blockquote>
<p>db.test.createIndex({age:1});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test.createIndex({age:"hashed"});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test.createIndex({score:1});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test.createIndex({score:"hashed"});</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>db.test.find({score:88,age:118}).explain()</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>是否采用索引交集的标志:</p>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<p>通过explain()查看执行计划的时候会出现AND_SORTED 或 AND_HASG阶段(stage)&nbsp;&nbsp;</p>


</blockquote>


</blockquote>
<blockquote>
<div>or与索引</div>


</blockquote>
<blockquote>
<div>&nbsp; &nbsp;&nbsp;db.test.find( { $or: [ { score: 88 }, { age: 8 } ] } ).explain()</div>


</blockquote>
<blockquote>
<div>索引覆盖</div>


</blockquote>
<blockquote>
<div>&nbsp; &nbsp;&nbsp;db.test.find({userid:681,score:33},{_id:0,age:1}).explain(1)</div>


</blockquote>
<blockquote>
<div>多列索引与排序</div>


</blockquote>
<blockquote>
<blockquote>
<div>db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({userid:1}); //索引可以优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({score:-1}); //索引可以优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({score:1}); //索引可以优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>&nbsp;db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({age:1}); //索引无法优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({age:-1});//索引无法优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>&nbsp;db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({userid:1,score:-1}); // 可以优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({userid:1,score:1}); //不可以优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>&nbsp;db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({userid:1,score:-1,age:1}); //索引可以优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>db.test.find({userid:1,score:{$gt:25}},{_id:0}).sort({userid:1,score:-1,age:-1}); //索引无法优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>&nbsp;db.test.find({userid:1,score:53,age:{$gt:29}}).sort({userid:1,score:-1,age:1}); //索引可以优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>&nbsp;db.test.find({userid:1,score:53,age:{$gt:29}}).sort({userid:-1,score:1,age:-1}); //索引可以优化排序</div>


</blockquote>


</blockquote>
<blockquote>
<blockquote>
<div>db.test.find({userid:1,score:53,age:{$gt:29}}).sort({userid:1,score:-1,age:-1});//索引无法优化排序</div>


</blockquote>


</blockquote>


</blockquote>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;多键索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 要索引一个包含数组值的字段,MongoDB会为数组中的每个元素创建一个索引键,这些多键索引支持针对数组字段的高效查询</p>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;多键索引可以在包含标量值(例如字符串、数字)和嵌套文档的数组上创建</p>
<blockquote>
<blockquote>
<blockquote>
<p>db.multi_key.createIndex({ratings:1},{background:true})</p>







</blockquote>







</blockquote>
<blockquote>
<blockquote>
<p>db.multi_key.insert({ _id: 5, type: "food", item: "aaa", ratings: [ 5, 8, 9 ] })</p>







</blockquote>







</blockquote>
<blockquote>
<blockquote>
<p>db.multi_key.insert({ _id: 6, type: "food", item: "bbb", ratings: [ 5, 9 ] })</p>







</blockquote>







</blockquote>
<blockquote>
<blockquote>
<p>db.multi_key.insert({ _id: 7, type: "food", item: "ccc", ratings: [ 9, 5, 8 ] })</p>







</blockquote>







</blockquote>
<blockquote>
<blockquote>
<p>db.multi_key.insert({ _id: 8, type: "food", item: "ddd", ratings: [ 9, 5 ] })</p>







</blockquote>







</blockquote>
<blockquote>
<blockquote>
<p>db.multi_key.insert({ _id: 9, type: "food", item: "eee", ratings: [ 5, 9, 5 ] })</p>







</blockquote>







</blockquote>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 限制:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; 不许创建两个数组组合索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;不允许创建hash多key索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;不能指定为shard key索引</p>
<p>文本索引</p>
<p>&nbsp; &nbsp; 一个集合最多只能创建一个文本索引</p>
<p>&nbsp; &nbsp; db.reviews.createlndex({ comment: "text" })</p>
<p>&nbsp; &nbsp; 可以对多个字段创建文本索引</p>
<p>&nbsp; &nbsp;&nbsp;db.reviews.createlndex({subject:"text", comment: "text" })&nbsp; &nbsp;&nbsp;</p>
<p>2dsphere索引</p>
<p>2d索引</p>
<p>Hash索引</p>
<p>&nbsp; &nbsp; 哈希索引通过索引字段的哈希值来维护条目</p>







</blockquote>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持使用哈希分片键的分片,基于哈希的分片使用字段的哈希索引作为分片键来区分分片数据</div>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用哈希分片键对集合进行分片会导致数据分布更加随机和均匀</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 哈希索引使用散列函数来计算索引字段的哈希值。哈希索引不支持多键(即数组)索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 创建哈希索引:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.coll.createindex({_id:"hashed"})</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;不可创建具有哈希索引字段的复合索引,或者对哈希索引指定唯一约束。但是,可以在一个字段上同时创建哈希索引和升序/降序(即非哈希)索引</p>
<p>&nbsp; &nbsp;&nbsp;索引属性&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;唯一索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;强制索引字段不含有重复值,默认情况下MongoDB会为_id字段创建唯一性索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;关键字:{unique:true}</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;唯一性索引创建:</p>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;db.unique1.createIndex({"user_id":1},{<span style="color: rgba(255, 44, 33, 1)">unique:true</span>})</p>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;db.unique2.createIndex({"name":1,"birthday":1},{unique:true})</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 限制:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果集合已经包含违反索引唯一约束的数据,则MongoDB无法再指定的索引字段上创建唯一索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不能在Hash索引上指定唯一约束</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 唯一索引对缺失列的处理</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果文档在唯一索引中没有索引字段的值,则索引将为此文档存储null值。由于唯一的约束,MongoDB将只允许一个缺失索引字段的文档。</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果有多个文档没有索引字段的至或缺少索引字段,则在添加唯一索引时将失败,并报出重复键错误。</p>
<div>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;唯一性索引为null的问题:</div>
<blockquote>
<div>
<blockquote>
<div><img src="https://img2018.cnblogs.com/blog/1063516/201906/1063516-20190611190622177-1310388256.png"></div>







</blockquote>







</div>







</blockquote>
<div>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;部分索引</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 部分文档仅索引符合指定过滤表达式的集合中的文档。存储需求更低,性能成本也更低</div>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;对集合的部分文档进行索引 :db.t.createIndex({ category: 1 },{&nbsp;<span style="color: rgba(255, 44, 33, 1)">partialFilterExpression</span>: { _id: { $gt: 2 } } } )&nbsp;</p>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;partialFilterExpression支持的选项:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;等值表达式(如 field: value或使用$eq操作符)</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $exists:true&nbsp; 表达式</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;$gt,$gte,$lt,$lte表达式</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;$type 表达式</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;第一层级的$and操作符</p>
<blockquote>
<p>&nbsp;部分索引的使用</p>







</blockquote>
<blockquote>
<blockquote>
<p>&nbsp;db.t.find({"category":"F array",_id:{$gt:1}}).explain() //无法利用部分索引</p>







</blockquote>
<blockquote>
<p>&nbsp;db.t.find({"category":"F array",_id:{$gt:3}}).explain() //可以利用部分索引</p>
<p>查询要使用部分索引则查询条件必须与索引表达式相同或是其子集</p>







</blockquote>







</blockquote>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;部分索引与唯一性</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.users.insert( { username: "david", age: 25 } )</p>
<blockquote>
<blockquote>
<p>db.users.insert( { username: "amanda", age: 26 } )</p>







</blockquote>
<blockquote>
<p>db.users.insert( { username: "andy", age: 30 } )</p>







</blockquote>
<blockquote>
<p>db.users.createIndex({ username: 1 },{ unique: true, partialFilterExpression: { age: { $gte: 20 } } })</p>







</blockquote>







</blockquote>
<blockquote>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;再次插入用户名为andy年龄为13(不在$gte:20的范围)的文档</p>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;db.users.insert( { username: "andy", age: 13} ) //插入成功</p>
<p>&nbsp; &nbsp; 限制</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; _id索引不可以是部分索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; shard key索引不可以是部分索引</p>







</blockquote>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;稀疏索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;指仅仅包含具有索引字段的文档,稀疏索引可以认为是部分索引的子集</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 稀疏索引的创建</p>
<blockquote>
<blockquote>
<p>db.collection.insert({ y: 1 } );</p>







</blockquote>
<blockquote>
<p>db.collection.createIndex( { x: 1 }, {<span style="color: rgba(255, 44, 33, 1)">&nbsp;sparse: true</span>&nbsp;} );</p>







</blockquote>







</blockquote>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;稀疏索引与hint</p>
<blockquote>
<p>db.collection.find().hint( { x: 1 } ).count();</p>
<p>db.collection.find().hint( { x: 1 } ) ;</p>







</blockquote>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;稀疏索引与唯一性</p>
<blockquote>
<p>db.collection.createIndex( { z: 1 } , { sparse: true, unique: true } )</p>
<p>db.collection.insert({y:2}) // 正常</p>
<p>db.collection.insert({y:3}) // 正常&nbsp;&nbsp;</p>







</blockquote>
<p>&nbsp;</p>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;TTL索引</p>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;是指MongoDB可以在特定的时间或者特定的时间段后自动删除集合文档的单列索引</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;TTL索引的规定</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;TTL索引字段必须是date类型或存储date类型数值的数组类型</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;TTL索引创建后会启动一个后台线程<span style="color: rgba(255, 44, 33, 1)">每分钟</span>启动进行文档删除(注:TTL索引删除不是严格意义上的1分钟)</div>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;MongoDB不支持组合TTL索引,否则过期特性会被MongoDB忽略</div>
<p>&nbsp;</p>
<blockquote>
<div>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TTL索引在索引字段值超过指定的秒数后过期文档;&nbsp;即,到期阈值是索引字段值加上指定的秒数。</p>
<p>&nbsp;  &nbsp; 如果字段是数组,并且索引中有多个日期值,则MongoDB使用数组中的<em>最低</em>(即最早)日期值来计算到期阈值。</p>
<p>  &nbsp; &nbsp;如果文档中的索引字段不是<span class="xref std std-term"><span style="color: rgba(0, 0, 0, 1)">日期</span></span>或包含日期值的数组,则文档将不会过期。</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 如果文档不包含索引字段,则文档不会过期。</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 在后台创建TTL索引时,TTL索引可以在构建索引时删除文档。如果在前台构建TTL索引,则在索引构建完毕后立即删除过期文档&nbsp;</p>

</blockquote>

</div>







</blockquote>
<blockquote>
<blockquote>
<p>&nbsp; &nbsp;&nbsp;<span style="color: rgba(73, 71, 71, 1)">TTL索引的创建</span></p>
<p><span style="color: rgba(73, 71, 71, 1)">  </span>db.exp.insert({lastDate:new Date()})</p>
<p>  db.exp.createIndex({"lastDate":1},{<span style="color: rgba(255, 44, 33, 1)">expireAfterSeconds</span>:60})</p>
<p> 在线修改TTL过期时间</p>
<p>  db.runCommand({collMod:"exp",index{keyPattern:{lastDate:1},expireAfterSeconds:120}})&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</p>

</blockquote>

</blockquote>
<p>&nbsp; &nbsp;&nbsp;查询数据库下的所有索引</p>
<p>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;db.getCollectionNames().forEach(function(collection) {</p>
<p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;indexes = db.getIndexes();</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;print("Indexes for " + collection + ":");</p>
<p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;printjson(indexes);});</p>
<p>&nbsp; &nbsp;索引统计信息</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; db.serverStatus(scale)的统计输出</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; metrics.queryexecutor.scanned:查询和查询计划评估期间扫描的索引项的总数。盖计数器与explain()输出中totalkeysexamamed意思相同</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; metrics.operation.scanAndOrder:表示无法使用索引排序的查询总次数</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; db.users.stats(scale)的统计输出</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; totalindexSize:所有索引的总大小。scale参数影响输出。如一个索引使用前缀压缩(WiredTiger的默认),则返回的大小为索引的压缩大小</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; indexSizes:指定集合上每个现有索引对应的键和大小。scale参数影响输出</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; db.stats(scale)的统计输出</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; indexes:在此数据库中所有集合的索引总数目</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; indexSize:在此数据库中创建的所有索引的总大小。scale参数影响输出</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp;索引设计原则</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 1、每个查询原则上都需要创建对应索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 2、单个索引设计应考虑满足尽量多的查询</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 3、索引字段选择及顺序需要考虑查询覆盖率及选择性</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 4、对于更新及其频繁的字段上创建索引需慎重</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 5、对于数组索引需要慎重考虑未来元素个数</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 6、对于超长字符串类型字段上慎用B数索引</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 7、并发更新较高的单个集合上不宜创建过多索引</p>
<p>&nbsp;</p>
<p><span data-wiz-span="data-wiz-span">MongoDB通用优化建议与实践<br></span></p>
<p>&nbsp; &nbsp; MongoDB查询缓存逻辑</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;索引选择基于采样代价模型,查询第一次执行如果有多个执行计划则会根据模型选出最优计划并缓存</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 语句执行会根据执行计划的表现对缓存进行重用或重建,如多次迭代都没有返回足够的文档则可能会触发重构</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 当MongoDB创建或删除索引时,会将对应集合的缓存执行计划清空并重新选择</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 如果MongoDB重新启动或关闭,则查询计划缓存会被清理然后依据查询进行重建</p>
<p>&nbsp; &nbsp; MongoDB查询缓存操作</p>
<blockquote>
<p>db.eof.find({x:1}); db.eof.find({x:3}).sort({y:1});&nbsp; 执行查询模拟查询计划缓存</p>
<p>db.eof.getPlanCache().listQueryShapes();&nbsp; &nbsp; 查询对应集合的查询计划缓存指纹</p>
<p>db.eof.getPlanCache().getPlansByQuery({"x":1},{},{"y":1});&nbsp; 通过指纹查看查询计划缓存信息&nbsp; &nbsp;</p>







</blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 注:查询指纹或叫形状是由query条件、sort条件及projection(投影)组成</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.eof.getPlanCache().clearPlansByQuery({"x":1},{},{"y":1})&nbsp;通过指定指纹清空对应查询计划缓存</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; db.eof.getPlanCache().clear()&nbsp; 清空对应集合所有执行计划的缓存信息</p>
<p>&nbsp; &nbsp;查询计划详解</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 支持查询计划的操作</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aggregate()</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count()</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; distinct()</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; find()</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; group()</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; remove()</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; update()</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; findAndModify()&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; 查询计划语法:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1、db.collection.explain(verbosity).&lt;method(...)&gt;&nbsp; 返回游标mongo shell 默认迭代</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2、db.collection.&lt;method(...)&gt;.explain(verbosity)&nbsp; &nbsp;返回json文档化结果</p>
<p>&nbsp; &nbsp; &nbsp;查询计划详解:</p>
<p>&nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;queryPlanner模式</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;MongoDB通过查询优化器对查询评估后选择一个最佳的查询计划(默认模式)</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; executionStats模式</p>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MongoDB通过查询优化器对查询进行评估并选择一个最佳的查询计划执行后返回统计信息</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于写操作则返回关于更新和删除操作的统计信息,但并不真正修改数据库数据</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于非最优执行计划不返回对于统计信息</p>







</blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;allPlansExecution模式</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 与上述两种模式的差别是除返回两种模式的信息的同时还包含非最优计划执行的统计信息&nbsp; &nbsp;</p>
<p>&nbsp;</p>
<blockquote>
<blockquote>
<p>ceshi27020_mongo:PRIMARY&gt; db.eof.find({x:2100}).explain()</p>

</blockquote>
<blockquote>
<p>{&nbsp; &nbsp;"queryPlanner" : {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //查询计划信息&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</p>

</blockquote>

</blockquote>
<blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "plannerVersion" : 1,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //查询计划版本</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "namespace" : "test.eof",&nbsp; &nbsp; //查询集合</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "indexFilterSet" : false,&nbsp; &nbsp; &nbsp; &nbsp; //查询过滤器</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "parsedQuery" : {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //查询具体条件</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "x" : {</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "$eq" : 2100</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "winningPlan" : {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//最优计划</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "stage" : "FETCH",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;//获取文档阶段</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "inputStage" : {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; // 过滤条件</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "stage" : "IXSCAN",&nbsp; &nbsp; //索引扫描阶段</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "keyPattern" : {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //要遍历的索引</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "x" : 1</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "indexName" : "idx_x",&nbsp; &nbsp;//索引名称</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "isMultiKey" : false,&nbsp; &nbsp; &nbsp; &nbsp; //是否是多key索引</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "isUnique" : false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//是否是唯一索引</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "isSparse" : false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //是否是稀疏索引</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "isPartial" : false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//是否是部分索引</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "indexVersion" : 1,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//索引版本号</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "direction" : "forward",&nbsp; &nbsp; &nbsp; &nbsp;//索引扫描方向(forward对应1,backward对应-1)</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "indexBounds" : {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //索引扫描的边界</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "x" : [&nbsp; ""]&nbsp; }&nbsp; }&nbsp; },&nbsp;"rejectedPlans" : [ ]&nbsp; },</p>

</blockquote>

</blockquote>
<blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; "serverInfo" : {</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "host" : "LeDB-VM-124064213",</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "port" : 27020,</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "version" : "3.2.20",</p>

</blockquote>
<blockquote>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "gitVersion" : "a7a144f40b70bfe290906eb33ff2714933544af8"&nbsp; },&nbsp; "ok" : 1}&nbsp; &nbsp; &nbsp;</p>

</blockquote>

</blockquote>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div>&nbsp;</div>
<p>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp;&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    删库的过程也是一直享受的过程!<br><br>
来源:https://www.cnblogs.com/DBA-3306/p/11005482.html
頁: [1]
查看完整版本: MongoDB查询及索引优化