MongoDB-M101-Indexes

MongoDB的索引是采用B-tree的结构。MongoDB默认对每个集合的”_id”都建立了唯一的正序索引,而且是不能删除的。

什么情况下适合使用索引

  • 对经常查询的字段需要构建索引
  • 只需获取集合的一小部分记录时(小于集合记录的一半),可以使用索引
  • 大部分应用都适合使用索引,经常要写入的应用就要先用性能工具分析是否应该使用索引

构建索引

简单索引

构建单一的索引,代码中的“1”表示的是正序,“-1”表示的是倒序。

db.posts.ensureIndex({'permalink': 1})
db.posts.ensureIndex({'postTime': -1})
联合索引

构建联合索引

db.posts.ensureIndex({'postTime': -1, 'permalink': 1,'title': 1})

构建联合索引的字段的先后顺序关系到查询的时候能否利用到联合索引,有就是说查询的时候要用到联合索引的一个字段过滤,那么那个字段之前的所有字段要在过滤条件中。

//利用到了联合索引
db.posts.find({'postTime': date})
db.posts.find({'postTime': date, 'permalink': permalink})
db.posts.find({'postTime': date, 'permalink': permalink, 'title': title})
//利用不到联合索引
db.posts.find({'permalink': permalink})
db.posts.find({'title': title})
db.posts.find({'postTime': date, 'title': title})
db.posts.find({'permalink': permalink, 'title': title})
唯一索引

构建唯一索引

db.posts.ensureIndex({'permalink': 1}, {unique:true})
删除重复记录索引

构建删除重复记录索引,dropDups要与unique一起使用,dropDups为true会删除posts中permalink重复了的记录,删除了就不能恢复了,要谨慎使用。

db.posts.ensureIndex({'permalink': 1}, {unique:true, dropDups:true})
Sparse Indexes

sparse用于有多条post记录,但是有些记录没有a字段,需要加上sparse: true才能对a生成索引,而没有a字段的记录中的索引值是null,对a进行查询或者排序的时候没有a字段的记录是不参与的。

db.posts.ensureIndex({'a':1},{sparse: true})
db.posts.find({a:null}) //No documents, because the query uses the index and there are no documents with title:null in the index.
MultiKey Indexes

在blog中一般的tags都是数组来的,对数组进行索引就是multiKey index,它会对数组中的每个值都构建索引。假如tags:[“mongodb”,”NoSQL”,”数据库”,”index”]。

db.posts.ensureIndex({tags: 1})
//构建出来的索引如下
{tags: "mongodb"}
{tags: "NoSQL"}
{tags: "数据库"}
{tags: "index"}

也可以对comments中的date构建索引

db.posts.ensureIndex({'comments.date': 1})

Compound Multikey Indexes May Only Include One Array Field。也就是构建db.foo.ensureIndex({a:1, b: 1})的索引,是不能插入包括多个数组的记录的,如db.foo.insert({a: [1, 2], b: [1, 2]}),但可以插入db.foo.insert({a: [1, 2], b: 1})db.foo.insert({a: 1, b: [1, 2]})

Geospatial Indexes

Geospatial indexes地理位置索引,对地理位置的索引原理的解析可以参考图解 MongoDB 地理位置索引的实现原理。假设stores中有'location':[x, y],对location构建索引,查询中可以使用$near

db.stores.ensureIndex({'location': '2d'})
db.stores.find({location: {$near: [x, y]}}).limit(10)
db.runCommand({geoNear: 'stores', near: [50, 50], spherical: true, maxDistance: 1})
Foreground and Backgound

构建索引的时候默认是foreground的,也可以使用background,如db.posts.ensureIndex({'permalink': 1}, {background:true})。foreground与background的区别是foreground的构建速度快,会进行写锁定;background的构建速度慢,不会进行锁定。

重建posts的所有索引可以使用db.posts.reIndex()

索引是有限制的,每个集合不能构建超过64个索引,而且索引的key的长度不能超过1024 bytes。

查询索引

查询数据库的所有索引

db.system.indexes.find()

查询单个集合的所有索引

db.posts.getIndexes()

获取索引的大小

db.posts.totalIndexSize()

使用hint指定查询当中使用的索引,也可以使用$natural指明按自然顺序查询不使用索引。

db.posts.find({'postTime': date, 'permalink': permalink}).hint( {'permalink': 1})
db.posts.find({'postTime': date, 'permalink': permalink}).hint( {$natural: 1})

可以使用explain对查询计划进行性能分析

db.posts.find({'postTime': date, 'permalink': permalink}).explain()

删除索引

“_id”的索引是删除不了的,删除除了”_id”之外的索引

db.posts.dropIndexes() 

删除指定的索引

db.posts.dropIndex({'postTime': -1, 'permalink': 1,'title': 1})