前言索引在数据库中的重要性不言而喻。Mysql使用B+数作为索引数据结构,对mysql的性能提升有很大的贡献。那么mongoDB使用的是什么数据结构呢?今天和大家聊聊mongoDB的索引。mongoDB的索引数据结构是什么?mongoDB支持哪些索引类型?mongo的索引数据结构是什么?网上对mongoDB的数据结构众说纷纭。有的说B-tree,有的说B-tree,有的说B+树。这是一个常识性的误解。Tree”,B-tree其实就是B-tree,中间的破折号只是用来连接的。官方文档《OnlyB-treeandB+tree》明确指出,在WiredTiger存储引擎中,可以同时支持B-Tree和LSM结构为了组织数据,“默认使用B+树”的数据结构在内存中维护了表的数据,说B树是正确的,因为B+树是B树的子集。对于WiredTiger存储引擎来说,collection所在的数据文件和对应的索引文件都是按照B-Tree结构组织的,不同的是数据文件对应的B-tree的叶子节点不仅会存储键名(keys),同时也存储真实的集合数据(values),所以数据文件的存储结构也可以认为是B+Treemongo中支持的一种索引类型,单个索引简单来说就是一个单个字段的索引。例如,db.children.createIndex({age:1})是equiva借给children表age字段创建升序索引(ascending(1)ordescending(-1))符合索引的复合索引其实是多个字段自合成一个索引,如db.children.createIndex({age:1,height:1})相当于给children表按年龄字段的升序和身高字段的升序建立索引。多键索引在MongoDB中可以“基于数组创建索引”。MongoDB为数组的每个元素创建一个索引值。多键索引支持对数组字段进行高效查询,例如([{_id:1,name:"xiaohong",age:"1",ratings:[1,2,3]})db.children.createIndex({ratings:1})但对于复合多键索引,“每个索引最多包含一个数组”。例如以下条件不能被索引([{_id:1,name:"xiaohong",age:"1",ratings:[1,2,3],teams:[1,3,4]})db...结果的2dsphere索引。有关地理空间索引的高级介绍,请参阅2dIndexInternals。文本索引MongoDB提供了一种文本索引,支持在集合中搜索字符串内容。这些文本索引不存储特定语言的停用词(如**“the”、“a”、“or”**),只存储一组词根的词干。有关文本索引和搜索的更多信息,请参阅文本索引。Hashed索引为了支持基于Hashed的分片,MongoDB提供了Hashed索引类型,对字段值的Hashed进行索引。这些索引在其范围内具有更随机的值分布,但仅支持相等匹配,不支持基于范围的查询。索引特点唯一索引MongoDB在创建集合时,会在_id字段上创建一个唯一索引,这也是默认的唯一索引。该索引主要用于区分文档,不能删除。创建方法是添加unique:truedb.children.createIndex({age:1},{unique:true})部分索引部分索引只对集合中匹配指定过滤表达式的文档进行索引。例如在children表中,为age大于5的数据创建升序索引db.children.createIndex({age:1},{partialFilterExpression:{age:{$gt:5}}})以节省存储空间并提高索引查询效率。比如文档2000年之前的数据是垃圾数据,不常用,那么可以根据大于2000的时间创建索引,索引的sparse属性保证索引只包含被索引的文档的条目领域。索引会跳过没有索引字段的文档。创建方法是添加sparse:truedb.children.createIndex({"age":1},{sparse:true})TTL索引TTL索引是MongoDB可以使用的一种特殊索引,它可以自动从集合中删除之后一定时期的文件。db.children.createIndex({"lastModifiedDate":1},{expireAfterSeconds:5})上面的case设置为5秒后过期。使用方法只需要在创建索引的时候加上expireAfterSeconds:5即可覆盖索引。所有需要查询的数据都在索引中,不需要从数据页中寻找数据。比如我此时为children表的时间创建了一个索引db.children.createIndex({age:1})这时候我在找一个两岁的孩子的时候就不需要了从数据页中查找数据db.children.find({age:2})prefixindex所有的前缀索引都可以被这个索引覆盖,不需要为这些前缀创建额外的索引,避免额外的开销。比如我此时为children表创建了“复合索引(多字段索引)”。db.children.createIndex({age:1,name:1,address:1})"所以其实这个一个索引相当于三个索引",分别是db.children.createIndex({age:1})db.children.createIndex({age:1,name:1})db.children.createIndex({age:1,name:1,address:1})结合索引的最佳方式索引的奇招ESR原则1.放精确匹配(Equal)在前2.排序(Sort)放在中间3.范围匹配(Range)在方块的末尾例如查询语句db.largeClass.find({className:"a",age:{$gte:5}}).sort(time:1)最好的索引建立应该是{className:1,time:1,age:1}E放在最前面,大家应该能看懂,用等值匹配过滤掉大量数据,“那为什么ESR不是ERS?”原因是因为如果范围匹配放在中间,那么后续我们排序的时候,只能进行“内存排序”,内存排序是非常耗资源的。当数据量很大时,可能会“面临多次磁盘读取和刷新内存操作”,这是非常耗时的,合理使用partsIndex对于一些比较大的文档来说,很多数据可能是无用的。比如文档里面有三年的数据,但是业务只需要最新的年份data,那么只能根据时间索引最近一年的数据。记得在创建索引的时候加上{background:true}在后台创建索引,以免影响mongoDB的正常运行,让其自动分配和创建如何查看是否使用了索引?MongoDB提供了“explainexecutionplan”,你可以清楚的看到你当前的查询语句使用了索引,使用方式也很简单,只需要在查询语句的右边加上.explain就行了。这里有一些“更重要的属性”。"executionTimeMillis":指的是我们语句的执行时间"docsExamined":文档扫描次数"totalDocsExamined":文档扫描入口"totalKeysExamined":索引扫描入口"stage":扫描类型,主要是COLLSCAN:全表扫描IXSCAN:indexscanFETCH:根据索引查找指定文档SHARD_MERGE:合并每个分片的返回数据SORT:表示在内存中排序LIMIT:使用limit限制返回的个数SKIP:使用skip跳过IDHACK:查询_idSHARDING_FILTER:通过mongos查询分片数据COUNT:使用db.coll.explain().count()进行计数操作counting:对于不使用索引的$or查询,stage返回TEXT:使用全文索引查询时,stage返回PROJECTION:limitedreturn字段返回stage时,“stage为IXSCAN”时,索引扫描为用过的
