MongoDB索引
索引部分
* 创建索引 和 查看索引
创建索引是为了考虑读数据的时候更快速。一般读比写更频密的时候,应该添加索引,假如写比读更频密,例如记录数据库操作日志,我们大可以不创建索引,从而使写的速度更快。
1.创建一个索引:
1:升序,-1:降序
db.things.ensureIndex( { x: 1} )
意思是创建一个针对x字段,升序的索引
db.things.ensureIndex( { y: -1} )
意思是创建一个针对y字段,降序的索引
db.things.ensureIndex( { x: 1, y: -1 } )
意思是创建一个针对x字段,升序的,针对y字段,降序的索引
db.things.ensureIndex( { zzz: 1 }, { background: true } )
意思是创建一个针对zzz字段,升序的索引,并且强制在后台执行。
适用情况:集合已经存在大量数据,创建索引将耗费一定时间,为避免阻塞后续的操作。
2.查看索引
db.things.getIndexes()
显示结果:
[
{
"v" : 1,
"key": {
"_id": 1
},
"ns": "test.things",
"name": "_id_"
},
{
"v" : 1,
"key": {
"x": 1
},
"ns": "test.things",
"name": "x_1"
},
{
"v" : 1,
"key": {
"y": -1
},
"ns": "test.things",
"name": "y_-1"
},
{
"v" : 1,
"key": {
"x": 1,
"y": -1
},
"ns": "test.things",
"name": "x_1_y_-1"
},
{
"v" : 1,
"key": {
"zzz": 1
},
"ns": "test.things",
"name": "zzz_1",
"background": true
}
]
"v":表示索引的版本,这个与MongoDB的版本号有关,在MongoDB 2.0或更早版本(不包括2.0版本)下创建的索引都会被标识为{ v: 0 },在MongoDB 2.0或更新版本下(包括2.0版本),索引会被标识为{ v: 1 },而且这两种索引格式是互相不兼容的,MongoDB 2.0的是用不了{ v: 0 }格式的索引,需要先删除后再重新创建索引。
“key”:索引键的信息 (键名: 1/-1)
“ns”:数据集合全称 (数据库名.集合名)
“name”:索引名称 (键名_1/-1)
注意:索引"_id_"为系统索引,不能删除。
* 文档索引
>db.things.insert( { name: 'person1', addr: {city: 'a', state:'d' } } )
>db.things.insert( { name: 'person1', addr: {city: 'b', state:'c' } } )
>db.things.insert( { name: 'person1', addr: {city: 'a', state:'e' } } )
>db.things.ensureIndex({ addr: -1 })
>var addr_1 = { city: 'a', state: 'd' }
>var addr_2 = { city: 'b', state: 'c' }
>var addr_3 = { city: 'a', state: 'e' }
>db.things.find( { addr: { $in : [addr_1, addr_2, addr_3] } } )
结果为:
{
"_id": ObjectId("529eaba252bf5eb74acdb35c"),
"name": "person1",
"addr": {
"city": "b",
"state": "c"
}
}
{
"_id": ObjectId("529eabc352bf5eb74acdb35d"),
"name": "person1",
"addr": {
"city": "a",
"state": "e"
}
}
{
"_id": ObjectId("529eab9552bf5eb74acdb35b"),
"name": "person1",
"addr": {
"city": "a",
"state": "d"
}
}
从搜索结果看出,优先按addr.city降序排,其次再按addr.state降序排。
假如没有索引,这三条记录的排序结果将会如何?
{
"_id": ObjectId("529eab9552bf5eb74acdb35b"),
"name": "person1",
"addr": {
"city": "a",
"state": "d"
}
}
{
"_id": ObjectId("529eaba252bf5eb74acdb35c"),
"name": "person1",
"addr": {
"city": "b",
"state": "c"
}
}
{
"_id": ObjectId("529eabc352bf5eb74acdb35d"),
"name": "person1",
"addr": {
"city": "a",
"state": "e"
}
}
就是与记录添加的顺序一致的
注意:
>db.things.find( { addr: { state:'e', city:'a' } } )
没把记录搜出来,原因,查询顺序跟索引顺序不一致。索引是先city后state的。
* 组合索引
索引包含两个键或以上
>db.things.insert( { name: 'person1', addr: {city: 'a', state:'d' } } )
>db.things.insert( { name: 'person1', addr: {city: 'b', state:'c' } } )
>db.things.insert( { name: 'person1', addr: {city: 'a', state:'e' } } )
>db.things.ensureIndex({'addr.city': -1, 'addr.state': -1})
>var addr_1 = { city: 'a', state: 'd' }
>var addr_2 = { city: 'b', state: 'c' }
>var addr_3 = { city: 'a', state: 'e' }
>db.things.find( { addr: { $in : [addr_1, addr_2, addr_3] } } )
结果为
{
"_id": ObjectId("529eab9552bf5eb74acdb35b"),
"name": "person1",
"addr": {
"city": "a",
"state": "d"
}
}---------------------------------------------------记录1(city:'a',state:'d')
{
"_id": ObjectId("529eaba252bf5eb74acdb35c"),
"name": "person1",
"addr": {
"city": "b",
"state": "c"
}
}---------------------------------------------------记录2(city:'b',state:'c')
{
"_id": ObjectId("529eabc352bf5eb74acdb35d"),
"name": "person1",
"addr": {
"city": "a",
"state": "e"
}
}---------------------------------------------------记录3(city:'a',state:'e')
db.things.find({ 'addr.state': {$in: ['c', 'd','e']} })
结果也是同上。
没有应用上索引,能应用上的话要写成如下:
db.things.find({ 'addr.city': {$in: ['a', 'b']} })
db.things.find().sort({ 'addr.city': -1 })
db.things.find().sort({ 'addr.city': -1 , 'addr.state': -1})
db.things.find( { 'addr.city':{ $in:['a','b'] }, 'addr.state': { $in:['e','d','c'] } } )
db.things.find( { 'addr.state': { $in:['e','d','c'] }, 'addr.city':{ $in:['a','b'] } } )
以上5种操作结果均为:
记录2(city:'b',state:'c')
记录3(city:'a',state:'e')
记录1(city:'a',state:'d')
从结果看,确实使用上{'addr.city': -1, 'addr.state': -1}符合索引,基本上下一个结论:
只要我们的搜索条件含有addr.city的字样就能应用上复合索引,否则应用不上的!
注意:
db.things.ensureIndex({'addr.city': -1, 'addr.state': -1})
写成db.things.ensureIndex({addr.city: -1, addr.state: -1}) 会报异常
异常:Unexpected token .。
错误写法汇总:不报错,但不能找到对应结果的情况
>db.things.find( { addr: { state:{ $in: ['e','d'] } } } )
>db.things.find( { addr: { city:'a', state:{ $in: ['e','d'] } } } )
* 唯一索引
唯一索引对应的字段在集合中最多出现一次。
>use mythings
>db.mythings.ensureIndex({ name:1, age:1}, {unique: true})
>db.mythings.insert({ name:'jimvin', age:'27'})
>db.mythings.insert({ name:'jimvin', age:'27'})
重复插入唯一键值相同的文档,会报异常:
E11000 duplicate key error index: mythings.mythings.$name_1_age_1 dup key:{ : "jimvin", : "27"}
注意:当你的集合含有记录,而你将要创建的唯一键并不是所有记录都存在,那么会报错。
>use things
>db.things.ensureIndex({ name:1, age:1}, {unique: true})
报错,由于things已有记录不是全部都包含name和age字段。
>db.mythings.getIndexes()
[
{
"v" : 1,
"key": {
"_id": 1
},
"ns": "test.things",
"name": "_id_"
},
{
"v" : 1,
"key": {
"name": 1,
"age": 1
},
"unique": true,
"ns": "mythings.mythings",
"name": "name_1_age_1"
}
]
* 强制使用索引
>db.mythings.ensureIndex({name:-1, age:-1} )
>db.mythings.insert( {name:'jimvin', age:27} )
>db.mythings.insert( {name:'jimvin', age:28} )
>db.mythings.insert( {name:'jimvin', age:29} )
>db.mythings.find({age:{$lt: 30}} )
结果为:
{
"_id": ObjectId("529ef3ce52bf5eb74acdb36b"),
"name": "jimvin",
"age": 27
}
{
"_id": ObjectId("529ef3d252bf5eb74acdb36c"),
"name": "jimvin",
"age": 28
}
{
"_id": ObjectId("529ef3d552bf5eb74acdb36d"),
"name": "jimvin",
"age": 29
}
没有使用降序,也就是没有使用索引来找,强制使用索引写法:
>db.mythings.find({age:{$lt: 30}} ).hint({name:-1,age:-1})
结果为:
{
"_id": ObjectId("529ef3d552bf5eb74acdb36d"),
"name": "jimvin",
"age": 29
}
{
"_id": ObjectId("529ef3d252bf5eb74acdb36c"),
"name": "jimvin",
"age": 28
}
{
"_id": ObjectId("529ef3ce52bf5eb74acdb36b"),
"name": "jimvin",
"age": 27
}
正合我们的意,它已经降序排列了。
引入一个问题,如何可靠获取操作是否应用上索引了?
MongoDB权威指南 中文版.pdf(http://www.open-open.com/doc/view/a5c6d0b3e866451dbd46d7f464ad61d9)指出另一方法:
>db.mythings.find({age:{$lt: 30}} ).explain()
结果:
{
“cursor”: "BasicCursor",
“isMultiKey”: false,
“n”: 3,
“nscannedObjects” :3,
“nscanned”:3,
“nscannedObjectsAllPlans” : 3,
“scanAndOrder” : false,
“indexOnly”: false,
“nYields”: 0,
“nChunkSkips”: 0,
“millis”:0,
“indexBounds”:{
},
“server”: "imac-xp:27017"
}
>db.mythings.find({age:{$lt: 30}} ).hint({name:-1,age:-1})explain()
{
“cursor”: "BasicCursor",
“isMultiKey”: false,
“n”: 3,
“nscannedObjects” :3,
“nscanned”:3,
“nscannedObjectsAllPlans” : 3,
“scanAndOrder” : false,
“indexOnly”: false,
“nYields”: 0,
“nChunkSkips”: 0,
“millis”:0,
“indexBounds”:{
“name”: [
[
“jimvin”,
"jimvin"
],
“age”: [
-1.7976931348623157e+308,
30
]
},
“server”: "imac-xp:27017"
}
然后, MongoDB权威指南 中文版中认为“indexBounds”不为{}就表示强制使用上索引了。
指出问题:
>db.mythings.ensureIndex({name:1,age:1})
>db.mythings.ensureIndex({name:-1,age:-1},{unique:true})
>db.mythings.find({name:{$in:['jimvin']}, age:{$lt:30}})
结果:
{
"_id": ObjectId("529ef3d552bf5eb74acdb36d"),
"name": "jimvin",
"age": 29
}
{
"_id": ObjectId("529ef3d252bf5eb74acdb36c"),
"name": "jimvin",
"age": 28
}
{
"_id": ObjectId("529ef3ce52bf5eb74acdb36b"),
"name": "jimvin",
"age": 27
}
显示优先选用唯一索引。
假如要强制使用{name:1,age:1}索引,写法如下:
>db.mythings.find({name:{$in:['jimvin']}, age:{$lt:30}}).hint({name:1,age:1})
结果:
{
"_id": ObjectId("529ef3ce52bf5eb74acdb36b"),
"name": "jimvin",
"age": 27
}
{
"_id": ObjectId("529ef3d252bf5eb74acdb36c"),
"name": "jimvin",
"age": 28
}
{
"_id": ObjectId("529ef3d552bf5eb74acdb36d"),
"name": "jimvin",
"age": 29
}
出现“bad hint”的情况:
如果我们创建的索引为
db.mythings.ensureIndex({ name:1, age:1}, {unique: true})
然后
>db.mythings.find({age:{$lt:30}}).hint({name:1,age:-1}).explain()
报异常:error{ “$err” : "bad hint", "code": 10113 }
* 删除索引
db.things.dropIndexes()
意思:删除things 集合所有索引
db.mythings.dropIndex({name:-1,age:-1},{unique:true})
意思:删除mythings 集合的唯一索引
本文来源 我爱IT技术网 http://www.52ij.com/jishu/4749.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
