索引简述
-
索引是什么
索引在数据库技术体系中占据了非常重要的位置,其主要表现为一种目录式的数据结构,用来实现快速的数据查询。通常在实现上,索引是对数据库表(集合)中的某些字段进行抽取、排列之后,形成的一种非常易于遍历读取的数据集合。目前绝大多数的数据库对于索引技术都有非常强大且稳定的支持。
索引的作用非常类似于一本书的目录。 -
索引的分类
- 按照索引包含的字段数量,可以分为单键索引和组合索引(或复合索引)。
- 按照索引字段的类型,可以分为主键索引和非主键索引。
- 按照索引节点与物理记录的对应方式来分,可以分为聚簇索引和非聚簇索引,其中聚簇索引是指索引节点上直接包含了数据记录,而后者则仅仅包含了一个指向数据记录的指针。
- 按照索引的特性不同,又可以分为唯一索引、稀疏索引、文本索引、地理空间索引等。
单键、复合索引
在MongoDB中,我们可以对集合中的某个字段或某几个字段创建索引,以book实体为例:
{
"_id" : ObjectId("67ab68cbf47317cf01307b3b"),
"title" : "book-0",
"type" : "technology",
"favCount" : 93,
"tags":['popular'],
"author" : {
"name" : "zale"
}
}
-
单字段索引
如果经常使用title这个字段进行搜索,可以为它创建一个单字段的索引> db.book.bookCollection.ensureIndex({ title:1}) { "createdCollectionAutomatically" : true, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
这里的“title:1”中的1表示所有采用的是升序排列。然而,在单字段的索引中,使用升序和降序并没有什么区别。
我们也可以对内嵌的文档字段创建索引:db.book.bookCollection.ensureIndex({auth.name:1}) -
复合索引
复合索引是多个字段组合而成的索引,其性质和单字段索引类似。但不同的是,复合索引中字段的顺序、字段的升降序对查询性能有直接的影响,因此在设计复合索引时需要考虑不同的查询场景。
例如,如果需要频繁地查询某分类下地book文档排名,可以按照分类,收藏数量创建一个复合索引,
db.book.bookCollection.ensureIndex({type:1,favCount:1})
数组索引
数组索引也被称为多值索引,当我们对数组型地字段创建索引时,这个索引就是多值的。多值索引在使用上与普通索引并没有什么不同,只是索引键上会同时产生多个值。
db.book.bookCollection.ensureIndex({
tags:1})
多值索引很容易与复合索引产生混淆,复合索引时多个字段的组合,而多值索引则仅仅是在一个字段上出现了多值。而实际上,多值索引也可以出现在复合索引上,例如:db.book.bookCollection.ensureIndex({type:1,tags:1})。然而,mongodb并不支持一个复合索引中同时出现多个数组字段。
地理空间索引
在移动互联网时代,基于地理位置的检索功能几乎时所有应用系统的标配。
mongodb为地理空间检索提供了非常方便的功能。地理空间索引就是专门用于实现位置检索的一种特殊索引。
db.store.insertOne({
location:{
type:"Point",coordinates:[-122.158574,37.449157]}})
db.store.ensureIndex({
location: "2dsphere" });
db.store.find({
location:{
$near:{
$geometry:{
type:"Point",coordinates:[-122.158,37.449]},$maxDistance:5000}}})
> {
"_id" : ObjectId("67ab829c2cee149b47c1e30e"), "location" : {
"type" : "Point", "coordinates" : [ -122.158574, 37.449157 ] } }
这里使用$near查询操作符,用于实现附近商家的检索,返回的数据结果会按距离排序
注意:mongodb的地理空间检索基于WGS84坐标系,在与一些地图平台集成时需要注意转换。
唯一性约束
在创建索引时,通过指定unique=true选项可以将其声明为唯一性索引,代码如下:
db.book.ensureIndex({
title:1},{
unique:true})
此后,如果尝试写入2个拥有相同标题的book文档,则会报错;另外,对于指定的字段已经存在重复记录的集合,如果尝试创建唯一性约束的索引,也会提示报错。
-
复合索引的唯一性
除了单字段索引,还可以为复合索引使用唯一约束。例如,如果只是希望分类下的书籍标题保持唯一性,那么可以建立复合式的唯一索引。db.book.ensureIndex({ type:1,title:1},{ unique:true})
-
嵌套文档的唯一性
唯一性约束同样可以用于嵌套文档的某个字段,这和普通索引没有什么区别,比如:db.book.ensureIndex({ author.name:1},{ unique:true})
但如果希望将整个嵌套文档作为唯一性的保证,那么在使用时可能会造成困扰,比如:
db.book.ensureIndex({ author:1},{ unique:true})
嵌套文档的唯一性约束是严格按照写入顺序进行比较的,如下代码所示,尽管写入的文档内容是一样的,但由于字段的顺序不一致,mongodb仍然认为这是不同的文档。为了避免困扰,尽量少用这种写法。
db.book.insert({ author:{ age:20,name:"Lwy"}}) db.book.insert({ author:{ name:"Lwy",age:20}})
-
数组的唯一性
如果对数组索引使用唯一性约束,那么可以保证所有的文档之间不会存在重叠的数组元素,代码如下:db.book.ensureIndex({ tags:1},{ unique:true}) db.book.insert({ tags:["t1","t2"]}) db.book.