与关系型数据库一样,合理的使用索引可以大幅提高MongoDB的查询效率,本文介绍基础索引、复合索引、文档索引等几种常用索引的使用
一、索引分类
MongoDB 提供了多样性的索引支持,索引信息被保存在system.indexes
中,且默认总是为_id创建索引,它的索引使用基本和MySQL
等关系型数据库一样。其实可以这样说说,索引是凌驾于数据存储系统之上的另一层系统,所以各种结构迥异的存储都有相同或相似的索引实现及使用接口并不足为奇。
1、基础索引与复合索引
1.1 、基础索引
创建索引时,可以是一个集合中的一个或多个字段。如,为用户表users的age字段,按升序[1(升序);-1(降序)]创建索引:
db.users.ensureIndex({age:1})
mongo会在创建表的时候将_id 自动创建的索引,此索引是不能够删除的。
当数据库中有大量数据时,创建索引的操作会非常耗时,我们可以指定background:true选项:
db.users.ensureIndex({age:1}, {background:true})
1.2、 复合索引(联合索引or组合索引)
跟其它数据库产品一样,MongoDB 也是有组合索引的,下面我们将在city 和age上建立组合索引。当创建组合索引时,字段后面的1 表示升序,-1 表示降序,是用1 还是用-1 主要是跟排序的时候或指定范围内查询 的时候有关的。为多个字段联合创建索引就是复合索引。如,为users表的age和city两个字段,分别按升序和降序创建索引:
db.users.ensureIndex({city:1,age:-1})
创建复合索引后,在使用时应当注意: 查询字段要在索引中存在,且顺序一致;如果索引中的首个字段没有出现在查询条件中,则不会用索引。
下面的查询都用到了这个索引:
db.factories.find( { "city" : "BeiJing", "age" : 18 } );
db.factories.find( { "city" : "BeiJing" } );
db.factories.find().sort( { "city" : 1, "age" : -1 } );
db.factories.find().sort( { "city" : 1 } );
2、文档索引
索引可以任何类型的字段,甚至文档:
如,users表中有以下数据:
{name:"扫地增", address:{ city:"北京", district:"海淀区" }}
可以为address子文档创建索引如下(在address列上创建索引):
db.users.ensureIndex({address:1})
对子文档创建索引时,也可以只对某一个或几个字段创建索引:
db.users.insert( { name: "扫地僧", addr: { city: "北京", district: "海淀区" } } )
建立索引后,查询时子文档的字段顺序要和索引建立的顺序一致:
// 下面这个查询将会使用刚刚建立的索引
db.users.find({address:{ city:"北京", district:"海淀区" }})
// 下面这个查询不会不会使用刚刚建立的索引
db.users.find({address:{ district:"海淀区", city:"北京" }})
**原因在于:在利用索引查询时用到的字段在查询中顺序要和索引创建时的顺序保持一致**
3、唯一索引和强制索引
3.1、 唯一索引
在关系型数据库中,我们可以为字段创建唯一索引,以保证字段值的唯一。在MongoDB中同样可以使用唯一索引,MongoDB创建唯一索引,在创建索引时添加unique:true选项即可。
如,为users表的email字段创建唯一索引:
db.users.ensureIndex({email:1}, {unique:true})
创建唯一索引后,当插入重复值时,MongoDB会报错:
> db.users.insert({email:'x@itbilu.com'})
WriteResult({ "nInserted" : 1 })
>//我们再插入一条
> db.users.insert({email:'x@itbilu.com'})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: itbilu.users.$mobile_1 dup key: { : null }"
}
})
3.2、 强制使用索引
在MongoDB的查询中,如果查询字段中的一个或几个字段已经创建了索引,我们可以使用hint()函数来强制使用索引。hint()在查询中是非常有效的一种优化手段:
db.users.find({age:{$lt:30}}).hint({name:1, age:1}).explain()
如,我们要查询users表中的多个字段,查询字段中的age字段创建过索引,可以使用hint()来强制赋索引查询:
db.users.find({name:'扫地僧', age:3}).hint({age:1})