我爱编程

Mongodb索引探索(一)

2014-05-06  本文已影响1407人  UncleYee

索引是数据库中的一个重要对象,主要用于支持高效查询操作。如果没有索引,数据库就只能进行全表扫描,效率将极为低下。mongodb的索引体系比较庞大,按照索引类型,我准备分这么几个部分来进行阐述:

概述

本文将简单介绍常用的基本索引类型,已经索引的相关操作。根据官方的文档,Mongodb有这么几种常见索引:

同时,mongodb提供了两个索引的属性:

好了,概念说了很多,来讲一下索引的具体操作吧。创建一个索引很简单,看看下面这些代码:


// 单键索引
db.Student.ensureIndex({code:1});

// 复合索引
db.Student.ensureIndex({name:1,time:-1})

// Multikey Index
db.Student.ensureIndex({faver.id:1});

//  唯一索引
db.Student.ensureIndex({code:1},{unique:1});

// 唯一索引同时删除重复值
db.Student.ensureIndex({code:1},{unique:1,dropDups:1});

// 唯一稀疏索引
db.Student.ensureIndex({code:1},{unique:1,sparse:1});


获取一个Collection上面的集合信息

// 单个Collection
db.Student.getIndexes();

// DB中所有的Index
db.system.indexes.find();

删除索引

// 删除在某个field上面的索引
db.Student.dropIndex({name:1});

// 根据索引名删除
db.system.indexes.remove({name:"code_-1"})

如何修改索引呢?没有特定修改命令,一般是先删除,然后创建新的索引。

系统运行一段时间以后,随着数据的累加,业务需求的变化,可能会需要对索引进行重建(rebuild),则可以做这个操作:

db.collection.reIndex()

rebuild会先删除集合上的所有索引,包括_id索引,然后重建。这种操作往往和耗时,最好在系统资源充足的时候做。

细节

1. 限制

mongodb对索引的使用和管理也有一些限制

上面列的只是一些大的限制,在具体场景中还有很多索引相互冲突,或者使用不当造成索引无法命中的情况,所以还要看看更细节的一些东西。

2. 使用策略

2.1 _id 主键索引

这个是系统自动创建的,不能删除,除非你Drop掉整个Collection。这个效率是非常高的,对于一些数据量很大,但是没有排序需求的集合(如日志表),在分页策略上应该使用_id来进行分页。

2.2 single 单键索引

mongodb 不限制你在任何field上面创建单键索引,但是一个查询一次只能使用一个索引($or子句可以使用多个),所以看看下面的情况会是这样的:

//存在两个索引:
{code:1},
{name:1}

//这里mongodb只会命中一个索引,具体是哪个由查询分析器决定
db.Student.find({code:{$lt:10},name:{$regex:/^a/}}).explain();
{
    "cursor" : "BtreeCursor name_1",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 1,
    "nscanned" : 1,
    "nscannedObjectsAllPlans" : 4,
    "nscannedAllPlans" : 4,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 46,
    "indexBounds" : {
        "name" : [
            [
                "a",
                "b"
            ]
        ]
    },
    "server" : "pormatoMacBook-Pro.local:27017"
}

索引还存在排序问题,{a:1}升序 / {a:-1}降序,但是对于单键索引,排序的时候升序降序都会命中。如:

db.Student.find().sort({name:1});
db.Student.find().sort({name:-1});

2.3 复合索引

多数情况下,应该考虑复合索引而非单键索引,因为复合索引会包含部分单键索引。例如:
对于索引:
{a:1,b:1,c:1}
相当于该集合拥有了:
{a:1} , {a:1,b:1} , {a:1,b:1,c:1}
但是:
{b:1} ,{c:1} , {b:1,c:1} 是无法命中的。

如果排序也希望命中索引的话,这里分为两种情况:

// 因为查询条件中不存在索引开始键(a:1),要想命中索引,排序必须以索引开始键开头
db.mycoll.find({b:{$gt:1}}).sort({a:1,b:1,c:1});
db.mycoll.find({a:{$gt:1}}).sort({b:1,c:1});

当然,排序里面还有更为细致的问题,就是查询条件如果有索引field的精准匹配(equal),则排序也能更简单:

db.mycoll.find({a:1}).sort({b:1});

同样,复合索引也存在索引反序问题,这里和单键索引一样,只有完全反序才能命中:
对于索引{a:1,b:-1}, {a:-1,b:1} 是可以命中的,反过来也成立。但是:{a:1,b:1}或者{a:-1,b:-1}是无法命中索引的。

3 MultiKey Index 多键索引

多键索引是作用在 array field上的element中的某个field上的索引。这个没有太多的特别之处,唯一要注意的是,如果一个索引是复合多键索引,那么这个索引的field中只能有一个array类型。例如:
{a:1,b:[{b1:1,b2:1}] 这个是Ok的, {a:[a1:1,a2:1],b:[{b1:1,b2:1}] 这种索引则是非法的。

其它

mongdb中还存在一种Cover Index的说法。它发生在如下的情况中:

代码


db.mycoll.find({a:{$lt:100}},{a:1,_id:0}});

这个时候查询条件的field和 查询域field 完全一样,并且这个field刚好能命中索引的话,这个查询效率将非常的高,因为mongodb不会再去硬盘进行扫描,而是直接将Index信息返回。

这里需要知道的是如果在下面两种情况下,Cover Index将无法生效

基本的索引类型就是这么多了,接下来还有Text , Geo ,hash等较为复杂的索引类型,这个在以后的文章中再来分析。

上一篇 下一篇

猜你喜欢

热点阅读