|
索引是用来加速查询的
准备数据
> db.users.insert({"username":"smith","age":48,"user_id":0})
> db.users.insert({"username":"smith","age":30,"user_id":1})
> db.users.insert({"username":"john","age":36,"user_id":2})
> db.users.insert({"username":"john","age":18,"user_id":3})
> db.users.insert({"username":"joe","age":36,"user_id":4})
> db.users.insert({"username":"john","age":7,"user_id":5})
> db.users.insert({"username":"simon","age":3,"user_id":6})
> db.users.insert({"username":"joe","age":27,"user_id":7})
> db.users.insert({"username":"jacob","age":17,"user_id":8})
> db.users.insert({"username":"sally","age":52,"user_id":9})
> db.users.insert({"username":"simon","age":59,"user_id":10})
|
一.单键索引
1.在没有创建索引前的执行计划(explain)
> db.users.find({"username":"joe"}).explain()
{
"cursor" : "BasicCursor",(cursor为BasicCursor说明该查询没有走上索引)
"nscanned" : 11,(查询的时候浏览了11个文档)
"nscannedObjects" : 11,
"n" : 2,(返回文档的数量)
"millis" : 0,(执行查询时间,这里的文档的username重复很高,所以看不出效果,在这里只给出测试方法)
"indexBounds" : {
}
}
|
2.创建索引和查看索引
> db.users.ensureIndex({"username":1},{"name":"index_username"})
> db.users.getIndexes()
[
{
"name" : "_id_",
"ns" : "test.users",
"key" : {
"_id" : 1
}
},
{
"_id" : ObjectId("53f9ec055724be10470e0f42"),
"ns" : "test.users",
"key" : {
"username" : 1
},
"name" : "index_username"
}
]
> db.system.indexes.find()
{ "name" : "_id_", "ns" : "test.blog", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.foo", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.c", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.users", "key" : { "_id" : 1 } }
{ "_id" : ObjectId("53f9ec055724be10470e0f42"), "ns" : "test.users", "key" : { "username" : 1 }, "name" : "index_username" }
|
3.在创建索引后的执行计划
> db.users.find({"username":"joe"}).explain()
{
"cursor" : "BtreeCursor index_username",(这里走上了索引)
"nscanned" : 2,
"nscannedObjects" : 2,
"n" : 2,
"millis" : 0,
"indexBounds" : {
"username" : [
[
"joe",
"joe"
]
]
}
}
|
4.删除索引,先查在删
> db.runCommand({"dropIndexes": "users", "index": "index_username"})
{ "nIndexesWas" : 2, "ok" : 1 }
|
二.复合索引(多键)
1.创建复合索引
> db.users.ensureIndex({"username":1,"age":1})
> db.system.indexes.find()
{ "name" : "_id_", "ns" : "test.blog", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.foo", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.c", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.users", "key" : { "_id" : 1 } }
{ "_id" : ObjectId("53f9f62c5724be10470e0f45"), "ns" : "test.users", "key" : { "username" : 1, "age" : 1 }, "name" : "username_1_age_1" }
> db.users.ensureIndex({"age":1,"username":1})
> db.system.indexes.find()
{ "name" : "_id_", "ns" : "test.blog", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.foo", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.c", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.users", "key" : { "_id" : 1 } }
{ "_id" : ObjectId("53f9f62c5724be10470e0f45"), "ns" : "test.users", "key" : { "username" : 1, "age" : 1 }, "name" : "username_1_age_1" }
{ "_id" : ObjectId("53f9f7ea5724be10470e0f46"), "ns" : "test.users", "key" : { "age" : 1, "username" : 1 }, "name" : "age_1_username_1" }
|
上面有两个索引username_1_age_1和age_1_username_1
2.在来看查询的执行计划
> db.users.find({"age":18,"username":/.*/}).explain()
{
"cursor" : "BtreeCursor age_1_username_1 multi",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"indexBounds" : {
"age" : [
[
18,
18
]
],
"username" : [
[
"",
{
}
],
[
/.*/,
/.*/
]
]
}
| 这里走上了age_1_username_1
我们希望走上的是username_1_age_1
所以应该强制让它走上username_1_age_1(用hint)
这里和oracle中对CBO调优类似,让查询按照我们想要的索引走,而不是根据优化器走
(小记:oracle中的调优技术:nestloop,hash join,merge join根据不同的需求进行选择)
> db.users.find({"age":18,"username":/.*/}).hint({"username":1,"age":1}).explain()
{
"cursor" : "BtreeCursor username_1_age_1 multi",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"indexBounds" : {
"username" : [
[
"",
{
}
],
[
/.*/,
/.*/
]
],
"age" : [
[
18,
18
]
]
}
}
|
3.修改索引
> db.users.ensureIndex({"age":1,"username":1},{"background":true})
作用索引的老化,不得不重新修改
|
三.地理空间索引
Mongodb为坐标平面查询用的
建立地理空间索引的键的值必须是一对值:一个包含两个数值的数组或包含两个键的内嵌文档(内嵌文档的键的名称无所谓),如:{“gps”:[0,100]},{“gps”:{“x”:-30,“y”:30}},{“gps”:{“latitude”:-180,“longitude”:180}}。
准备数据
> db.map.insert({"location":[50,100],"desc":"coffee"})
> db.map.insert({"location":[-70,30],"desc":"coffeeshop"})
> db.map.insert({"location":[100,150],"desc":"muffins"})
> db.map.insert({"location":[-90,-20],"desc":"espresso"})
|
1.创建索引
> db.map.ensureIndex({"location":"2d","desc":1}) 这里用2d且要用双引号
> db.map.getIndexes()
[
{
"name" : "_id_",
"ns" : "test.map",
"key" : {
"_id" : 1
}
},
{
"_id" : ObjectId("53fa02be5724be10470e0f4c"),
"ns" : "test.map",
"key" : {
"location" : "2d",
"desc" : 1
},
"name" : "location__desc_1"
}
]
|
2.查找最近的咖啡店用”$near"
> db.map.find({"location":{"$near":[-70,100]},"desc":"coffee"}).limit(1)
{ "_id" : ObjectId("53fa01625724be10470e0f48"), "location" : [ 50, 100 ], "desc" : "coffee" }
|
3.在矩形里查找
> db.map.find({"location":{"$within":{"$box":[[-70,0],[50,150]]}},"desc":"coffeeshop"})
{ "_id" : ObjectId("53fa01a65724be10470e0f49"), "location" : [ -70, 30 ], "desc" : "coffeeshop" }
| 通过{"$box":[[-70,0],[50,150]]}指定一个矩形,其左下角和右上角坐标;”$within”指定查询在这个范围内的点。
4.在圆形区域查找
> db.map.find({"location":{"$within":{"$center":[[-70,0],50]}},"desc":"coffeeshop"})
{ "_id" : ObjectId("53fa01a65724be10470e0f49"), "location" : [ -70, 30 ], "desc" : "coffeeshop" }
| {"$center":[[-70,0],50]},指定了圆形的圆心坐标和半径; ”$within”指定查询在这个范围内的点。
|
|