【知识小课堂】4 之 索引

索引类型

                 mongoDB 的索引在存储结构都是一样的,但是根据不同的应用需求,还是分成了:唯一索引,稀疏索引,复合索引


1.唯一索引

            MONGODB 在默认建立文档时,都会自动添加一个:“_id” 字段,而此字段默认建立唯一索引;


            如果我们要使一个键值在文档中唯一,我们就要在此字段建立一个唯一索引,语法如下:


db.users.ensureIndex({account:1},{unique:true})


和其它数据库一样,唯一索引,此字段是允许值为NULL 的,但只允许有一条。


当然,我们也可以在多个字段中建立一个唯一索引:


db.users.ensureIndex({mobile:1,email:1},{unique:true})
 

2.稀疏索引

有这样一个问题:

如果某个字段,如果它存在,那么必须是唯一,因为 会把null当做值,如果定义了唯一索引,那么此字段只能存在一个null值的记录。

这时我们可以使用以下方法定义这个索引:


db.user.ensureIndex({email:1},{“unique”:true,”sparese”:true})



当然,上面是为了方便理解而举的一个例子。其实 稀疏索引并不是必须是唯一索引。


db.user.ensureIndex({email:1},{”sparese”:true})


我们也看一个 稀疏索引查询


> db.foo.find()
{ "_id" : 0 }
{ "_id" : 1, "x" : 1 }
{ "_id" : 2, "x" : 2 }
{ "_id" : 3, "x" : 3 }
> db.foo.find({x:{$ne:2}})
{ "_id" : 0 }
{ "_id" : 1, "x" : 1 }
{ "_id" : 3, "x" : 3 }

 

在文档的x 键建立一个 [稀疏索引]


> db.foo.ensureIndex({x:1},{sparse:true})
> db.foo.getIndexes()
[{"v" : 1,
"key" : {
	"_id" : 1
	},
	"ns" : "test.foo",
	"name" : "_id_"
	},
{
	"v" : 1,
	"key" : {
	"x" : 1
	},
	"ns" : "test.foo",
	"name" : "x_1",
	"sparse" : true
}
]

完成后,我们再来查询看看:


> db.foo.find({x:{$ne:2}})
{ "_id" : 1, "x" : 1 }
{ "_id" : 3, "x" : 3 }
> 



看到,这时查询结果,已排除了 没有键 X 的文档 _id:0 了。

就是因为在建立索引时,“_id”=0 的文档,不会包含在索引中。


当然,如果你需要查询到 那些不包含 “x” 的 文档。你可以使用  hint() 来强制全表或其它索引搜索。

比如我下面的代码:

> db.foo.find({x:{$ne:2}}).hint({"_id":1})
{ "_id" : 0 }
{ "_id" : 1, "x" : 1 }
{ "_id" : 3, "x" : 3 }

全表索引:


> db.foo.find({x:{$ne:2}}).hint({$natural:1})
{ "_id" : 0 }
{ "_id" : 1, "x" : 1 }
{ "_id" : 3, "x" : 3 }
> 

3.复合索引

 复合索引同样可用于局部属性的搜索,但必须依照索引字段顺序。比如创建索引字段顺序"a,b,c",那么仅对"a,b,c""a,b""a"查询有效,而对"b,c" 之类的组合无效。

上面这段话,在mongodb 也有效。

> db.order_detail.find()
{ "_id" : 1, "cust_id" : 1, "order_id" : 1, "prod_id" : 1 }
{ "_id" : 2, "cust_id" : 1, "order_id" : 1, "prod_id" : 2 }
{ "_id" : 3, "cust_id" : 2, "order_id" : 2, "prod_id" : 2 }
{ "_id" : 4, "cust_id" : 3, "order_id" : 2, "prod_id" : 1 }
{ "_id" : 5, "cust_id" : 3, "order_id" : 3, "prod_id" : 3 }
> db.order_detail.ensureIndex({cust_id:1,order_id:1})



> db.order_detail.getIndexes()
[{"v" : 1,
"key" : {"_id" : 1},
"ns" : "test.order_detail","name" : "_id_"},
{"v" : 1,
"key" : {"cust_id" : 1,"order_id" : 1},
"ns" : "test.order_detail",
"name" : "cust_id_1_order_id_1"}]

上面文档在建立完成复合索引后,我们来查询一下数据,并看看执行计划:


> db.order_detail.find({order_id:1}).explain()
{"cursor" : "BasicCursor",
	"isMultiKey" : false,
	"n" : 2,
	"nscannedObjects" : 5,
	"nscanned" : 5,
	"nscannedObjectsAllPlans" : 5,
	"nscannedAllPlans" : 5,
	"scanAndOrder" : false,
	"indexOnly" : false,
	"nYields" : 0,
	"nChunkSkips" : 0,
	"millis" : 0,
	"indexBounds" : {},
	"server" : "localhost.localdomain:27017"
}

我指定了一个组合索引中后面一个字段进行查询可以看到,确实没用到索引

再来看看下面代码:

> db.order_detail.find({order_id:1}).sort({cust_id:1}).explain()
{"cursor" : "BtreeCursor cust_id_1_order_id_1",
	"isMultiKey" : false,"n" : 2,"nscannedObjects" : 2,
	"nscanned" : 4,	"nscannedObjectsAllPlans" : 4,
	"nscannedAllPlans" : 6,	"scanAndOrder" : false,
	"indexOnly" : false,	"nYields" : 0,
	"nChunkSkips" : 0,	"millis" : 0,
	"indexBounds" : {
		"cust_id" : [[{"$minElement" : 1},
			{"$maxElement" : 1}	]
		],
		"order_id" : [[1,1]	]
	},
	"server" : "localhost.localdomain:27017"
}
> 


我指定了一个组合索引中 后面一个字段进行查询,但我增加了一个第一个字段的排序。这时可以看到,它用到索引了。

看来还是有办法解决复合索引的缺陷的。

还有办法:


>db.order_detail.find({order_id:1}).hint({cust_id:1,order_id:1}).explain()
{"cursor" : "BtreeCursor cust_id_1_order_id_1",
	"isMultiKey" : false,
	"n" : 2,"nscannedObjects" : 2,
	"nscanned" : 4,"nscannedObjectsAllPlans" : 2,
	"nscannedAllPlans" : 4,
	"scanAndOrder" : false,
	"indexOnly" : false,"nYields" : 0,
	"nChunkSkips" : 0,"millis" : 0,
	"indexBounds" : {
		"cust_id" : [[{"$minElement" : 1},
			{"$maxElement" : 1}]],
		"order_id" : [[1,1]]
	},
	"server" : "localhost.localdomain:27017"
}
> 


我指定了一个组合索引中后面一个字段进行查询,但我使用了指定索引进行查询。

这时看到,查询也用到索引了。

但这时因为第一个字段为空值,在进行索引检索时,肯定会搜索更多的数据。

有可能是 fullindexsearch.

但总比全表索搜好吧。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值