MongoDB 单字段索引和复合索引

MongoDB中常见的索引有单字段索引和复合索引.

单字段索引

没有索引的查询

>db.users.find({username:"user0115"}).explain(true)
//以下是其中的一部分, 可以看到docsExamined为100W,即扫描了所有的文档, 查询时间为executionTimeMillis为318ms
//db.users.find({username:"user123456"}).explain(true).executionStats.executionTimeMillis 可以直接查看花费的时间

    "executionStats" : {
    .....
        "executionSuccess" : true,
        "executionTimeMillis" : 318,
        "nReturned" : 1,
        "totalDocsExamined" : 1000000,
        "totalKeysExamined" : 0
    .....
    }

建立索引

这次我们对username新建一个索引, 1表示增序排列:

>db.users.ensureIndex({"username":1})

索引分析

db.users.find({username:"user0115"}).explain(true)
//返回如下, 其中indexName表示使用到了这个索引, executionTimeMillis为0ms,totalDocsExamined为1, 只扫描了1个文档, 改变非常的大
....
                "indexName" : "username_1",
                "indexVersion" : 1,
                "invalidates" : 0,
                "isEOF" : 1,
                "isMultiKey" : false,
                "isPartial" : false,
                "isSparse" : false,
                "isUnique" : false,
                "keyPattern" : {
                    "username" : 1
                }
......
        "executionSuccess" : true,
        "executionTimeMillis" : 0,
        "nReturned" : 1,
        "totalDocsExamined" : 1,
        "totalKeysExamined" : 1
.....

注意事项

新建索引后, 每次写操作(插入, 更新, 删除)文档都要更新索引. MongoDB限制每个集合上最多只能有64个索引. 通常在一个特定的集合上, 不应该拥有两个以上的索引.
通常索引应该建立在常用的查询的字段上, 对于不常用的字段不应该建立索引.

复合索引

索引所对应的值是按一定顺序排列的,因此使用索引对文档进行排序非常快.然而进行排序时, 只能使用到一个索引, 我们需要把希望使用的索引放到第一个位置.
在以下的例子中, 由于集合中数据量比较大, 直接排序会超过MongoDB对单次操作的内存限制32M. 所以我们在以下的操作使用的users集合数据量为10W.

>db.users10W.find().sort({"age": 1 , "username" : 1}).limit(1000)

上面的例子中先对age进行排序, 然后再对username排序.我们已经对username建立了索引, 但是这个查询并不能使用到username索引.
查询其explain信息

        .....
        "memLimit" : 33554432,
        "memUsage" : 98341,
        .....
        "executionSuccess" : true,
        "executionTimeMillis" : 124,
        "nReturned" : 1000,
        "totalDocsExamined" : 100000,
        "totalKeysExamined" : 0
        .....

发现其内存使用了98K, 扫描了所有的10W条文档, 耗时124ms.

建立复合索引

如果这个查询比较普遍的话, 可以在对这两个字段一起建立索引, 称为复合索引(compound index). 如果查询中有多个排序或者查询条件中有多个键, 这个索引就会很有用.

>db.users10W.ensureIndex({"age":1,"username":1})
>db.users10W.getIndexes()
{
    "key" : {
        "_id" : NumberInt("1")
    },
    "name" : "_id_",
    "ns" : "test.users10W",
    "v" : NumberInt("1")
},

{
    "key" : {
        "username" : 1
    },
    "name" : "username_1",
    "ns" : "test.users10W",
    "v" : NumberInt("1")
},
{
    "key" : {
        "age" : 1,
        "username" : 1
    },
    "name" : "age_1_username_1",
    "ns" : "test.users10W",
    "v" : NumberInt("1")
}

复合索引分析

可以看到第3个是刚刚新加的复合索引.
再次进行上面的查询和explain信息. 返回1000个文档, 也只扫描了1000个文档, 耗时1ms. 之前的索引没有使用时, 扫描了所有文档, 耗时124ms.

        ...
        "executionSuccess" : true,
        "executionTimeMillis" : 1,
        "nReturned" : 1000,
        "totalDocsExamined" : 1000,
        "totalKeysExamined" : 1000
        .....
                    "indexName" : "age_1_username_1",
                    "indexVersion" : 1,
                    "isMultiKey" : false,
                    "isPartial" : false,
                    "isSparse" : false,
                    "isUnique" : false,
                    "keyPattern" : {
                        "age" : 1,
                        "username" : 1
                    },
        ....

结论

不管是简单索引还是复合索引. 在使用正确的情况下, 都大大加快了查询速度.

语句 集合大小 索引情况 花费时间 扫描文档数
db.users.find({username:”user0115”}) 1M 318ms 1M
db.users.find({username:”user0115”}) 1M db.users.ensureIndex({“username”:1}) 0ms 1
db.users10W.find().sort({“age”: 1 , “username” : 1}).limit(1000) 0.1M 124ms 0.1M
db.users10W.find().sort({“age”: 1 , “username” : 1}).limit(1000) 0.1M db.users10W.ensureIndex({“age”:1,”username”:1}) 1ms 1000

要点:
查询索引:

db.users10W.getIndexes()

建立索引:

简单索引: db.users.ensureIndex({“username”: 1})
复合索引: db.users10W.ensureIndex({“age”: 1,”username”: 1})

删除索引

db.users10W.dropIndex(“username_1”)

你可能感兴趣的:(MongoDB,数据库,NoSQL)