您的位置:首页 > 数据库 > Mongodb

MongoDB 单字段索引和复合索引

2016-12-25 16:33 357 查看
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”})1M318ms1M
db.users.find({username:”user0115”})1Mdb.users.ensureIndex({“username”:1})0ms1
db.users10W.find().sort({“age”: 1 , “username” : 1}).limit(1000)0.1M124ms0.1M
db.users10W.find().sort({“age”: 1 , “username” : 1}).limit(1000)0.1Mdb.users10W.ensureIndex({“age”:1,”username”:1})1ms1000
要点:

查询索引:

db.users10W.getIndexes()

建立索引:

简单索引: db.users.ensureIndex({“username”: 1})

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

删除索引

db.users10W.dropIndex(“username_1”)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: