索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。索引通常能极大的提高查询的效率。例如userInfo集合里,有4个文档(省去了_id字段)。如果现在需要查询所有年龄为18岁的人,db.userInfo.find({age:18})会遍历所有文档,然后根据每个文档的位置信息,读出文档。当集合中的文档数量达到百万、千万或更多的情况下,对集合进行全表扫描,那开销将会非常大。

{
    "name":"xiaoming",
    "age":18,
    "height":178
}
{
    "name":"xiaohua",
    "age":17,
    "height":168
}
{
    "name":"xiaomi",
    "age":16,
    "height":167
}
{
    "name":"xiaobu",
    "age":18,
    "height":187
}

为了提高查找效率,可以对userInfo集合的age字段建立索引。建立索引后,MongoDB会额外存储一份按age字段升序排序的索引数据,索引结构类似如下:

age

位置信息

16

位置3

17

位置2

18

位置1

18

位置4

这样就可以快速的从索引里找出某个age值对应的位置信息,然后根据位置信息,读取对应的文档。那么如何添加索引呢?其实mongoDB在默认情况下就会为文档的_id字段添加索引。其他字段的索引添加需要手动来操作,具体如下。

创建索引

db.collection.ensureIndex(keys, options)方法在索引不存在的情况下,会在指定字段上创建索引。从3.0.0版本开始不推荐使用,现在用的另外一个名字:db.collection.createIndex()。例如:

>db.userInfo.createIndex({"age":1})

上面脚本中,为表userInfoage字段,指定按升序创建索引,如果想降序来创建,只需将字段的值改为"-1"即可。这种索引叫单字段索引(single field index)
该方法也可同时为多个字段创建索引,这种索引也叫复合索引。首先按第一个字段排序,第一个字段相同的文档按第二个字段排序,依次类推。例如:

>db.userInfo.createIndex({"age":1,"height":1})

当索引的字段为数组时,创建出的索引称为多key索引,多key索引会为数组的每个元素建立一条索引,比如userInfo集合中加入一个字段skills(数组)用于描述擅长技能。

{
    "name":"xiaoming",
    "age":18,
    "height":178,
    "skills":["painting","sing"]
}

需要查询相同技能的人就可以利用skills字段的多key索引。

>db.userInfo.createIndex({"skills":1})  //自动创建多key索引

注意: 虽然索引可以提供查询的效率,但是同时也降低了insert和update的效率。因为insert和update操作可能会重建索引,所以索引数不宜过多,一个表的索引数最好不要超过6个。

索引一般用在返回结果只是总体数据的一小部分的时候。根据经验,一旦返回的数据达到集合的一半时,就不要使用索引了。

若是已经对某个字段建立了索引,又想在大规模查询时不使用它(因为使用索引可能会低效),可以使用自然排序(指按照磁盘上的存储顺序返回数据),用{"$natural":1}来强制mongodb禁用索引。如果某个查询不用索引,mongodb就会做全表扫描,即逐个扫描文档,遍历整个集合以找到结果。

参考文章

1.MongoDB索引原理