MongoDB索引Index分类及其实现原理
与MySQL一样,MongoDB中也使用索引提高查询效率。那索引是什么呢?索引是⼀种单独的、物理的对数据库表中⼀列或多列的值进⾏排序的⼀种存储结构,它是某个表中⼀列或若⼲列值的集合和相应的指向表中物理标识这些值的数据⻚的逻辑指针清单。索引的作⽤相当于图书的⽬录,可以根据⽬录中的⻚码快速找到所需的内容。索引⽬标是提⾼数据库的查询效率,没有索引的话,查询会进⾏全表扫描(scan every document in a collection) ,数据量⼤时严重降低了查询效率。
默认情况下Mongo在⼀个集合(collection)创建时,⾃动地对集合的_id创建了唯⼀索引。MongoDB中索引类型如下:
1、单键索引 (Single Field)
MongoDB⽀持所有数据类型中的单个字段索引,并且可以在⽂档的任何字段上定义。对于单个字段索引,索引键的排序顺序⽆关紧要,因为MongoDB可以在任⼀⽅向读取索引。
单个例上创建索引:
db.collection_name.createIndex({"字段名":排序⽅式})
1表示升序,-1表示降序。
需要注意的是:MongoDB中有一个特殊的单键索引 ——过期索引 TTL ( Time To Live)。TTL索引是MongoDB中⼀种特殊的索引, 可以⽀持⽂档在⼀定时间之后⾃动过期删除,⽬前TTL索引只能在单字段上建⽴,并且字段类型必须是⽇期类型。
db.collection_name.createIndex({"⽇期字段":排序⽅式}, {expireAfterSeconds: 秒数})
2、复合索引(Compound Index)
实际生产中通常需要在多个字段的基础上搜索表/集合,这是⾮常频繁的。 如果是这种情况,可能会考虑在MongoDB中制作复合索引。 复合索引⽀持基于多个字段的索引,这扩展了索引的概念并将它们扩展到索引中的更⼤域。
制作复合索引时要注意的重要事项包括:字段顺序与索引⽅向。
db.collection_name.createIndex( { "字段名1" : 排序⽅式, "字段名2" : 排序⽅式 } )
3、多键索引(Multikey indexes)
针对属性包含数组数据的情况, MongoDB⽀持针对数组中每⼀个element创建索引, Multikey indexes⽀持strings, numbers和nested documents。
4、地理空间索引(Geospatial Index)
针对地理空间坐标数据创建索引。
1)2dsphere索引,⽤于存储和查找球⾯上的点
2)2d索引,⽤于存储和查找平⾯上的点
5、全⽂索引
全文索引是MongoDB提供的专门针对string内容的⽂本查询, Text Index⽀持任意属性值为string或string数组元素的索引查询。需要注意的是:⼀个集合仅⽀持最多⼀个Text Index,中⽂分词不理想 推荐ES。
db.collection_name.createIndex({"字段": "text"})
db.collection_name.find({"$text": {"$search": "coffee"}})
6、哈希索引 Hashed Index
该索引针对属性的哈希值进⾏索引查询,当要使⽤Hashed index时, MongoDB能够⾃动的计算hash值,⽆需程序计算hash值。
db.collection_name.createIndex({"字段": "hashed"})
注意: hash index仅⽀持等于查询,不⽀持范围查询。
通过以上索引分类,对比MySQL索引分类(MySQL索引原理之索引类型 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com))差别还是相当大的。
另外通过db.mycoll.help可以查看集合相关的方法。上面已经实践了索引的建立,那索引的查看、修改、删除等分别是用什么方法呢?下面揭晓:
创建索引并在后台运⾏
db.collection_name.createIndex({"字段":排序⽅式}, {background: true});
获取针对某个集合的索引
db.collection_name.getIndexes()
索引的⼤⼩
db.collection_name.totalIndexSize()
索引的重建
db.collection_name.reIndex()
索引的删除
db.collection_name.dropIndex("INDEX-NAME")
db.collection_name.dropIndexes()
需要注意的是:_id 对应的索引是删除不了的(这个系统根据_id会自动创建索引)
MongoDB中索引如何实现的呢?关于索引的实现原理与MySQL索引实现原理对比进行分析:MySQL是关系型数据库,数据的关联性是⾮常强的,区间访问是常⻅的⼀种情况,底层索引组织数据使⽤B+树, B+树由于数据全部存储在叶⼦节点,并且通过指针串在⼀起,这样就很容易的进⾏区间遍历甚⾄全部遍历。 MongoDB使⽤B-树,所有节点都有Data域,只要找到指定索引就可以进⾏访问,单次查询从结构上来看要快于MySQL。
对于B-树及B+树的结构在MySQL索引原理之索引原理 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)已经有详细的介绍,可以看出最核⼼的区别主要有俩:⼀个是数据的保存位置,⼀个是相邻节点的指向。就是这俩造成了MongoDB和MySql的差别:
1) B+树相邻接点的指针可以⼤⼤增加区间访问性,可使⽤在范围查询等,⽽B-树每个节点 key 和 data 在⼀起适合随机读写 ,⽽区间查找效率很差。
2) B+树更适合外部存储,也就是磁盘存储,使⽤B-结构的话,每次磁盘预读中的很多数据是⽤不上的数据。因此,它没能利⽤好磁盘预读的提供的数据。由于节点内⽆ data 域,每个节点能索引的范围更⼤更精确。
3)注意这个区别相当重要, B-树每个节点即保存数据⼜保存索引导致树的深度⼤,所以磁盘IO的次数多, B+树只有叶⼦节点保存,较B树⽽⾔深度⼩,磁盘IO少,有利于区间访问。