Mongodb索引学习
为什么需要索引
如果没有索引,mongodb必须扫描每一个文档集合选择匹配的查询记录;这样扫描一遍造成的资源消耗是非常大的。索引是一种特殊的数据结构,它保存了小部分简单的集合数据,或者是一些特殊的字段并将其排序。可以举个特别恰当的例子,没有索引的数据库就像是一本字典没有前面的索引目录,每次查一个单词都需要从头遍历到呢个单词的位置;而索引的出现就是为了大大的优化数据库查询的效率。
索引优化
即使是索引,不同类型的索引也会有不同的优化程度。Mongodb的索引默认使用的是B-tree这一特殊的数据结构:
B-tree索引具有分层树结构,树顶部是header block,包含指向任何给定范围的键值的适当branch block的指针。而branch block通常会指向适当的leaf block以获得更具体的范围,或者对于更大的索引会继续指向branch block然后到leaf block,因为leaf block上才包含一个键值列表和指向磁盘上文档位置的指针。
而B-tree索引具有以下优点:
1.由于每个叶子节点处于相同的深度,所以性能是非常可预测的。 从理论上讲,集合中的任何文档都不会超过三或四次I/O。
2.B树为大型集合提供了良好的性能,因为深度最多为四个(一个头部块,两个分支块级别和一个叶子块级别)。 一般来说,没有任何文件需要四个以上的I/O来定位。 实际上,因为头部块几乎总是已经加载到内存中,而分支块通常加载到内存中,所以实际的物理磁盘读取次数通常只有一次或两次。
3.因为与前一个和后一个叶子块的链接,所以B-tree索引支持范围查询以及精确的查找是可行的。
借助索引Mongodb可以高效的匹配到需要查询的数据,以官方的图为例:
图中,score的index从min到max,我们就可以通过score索引高效的进行range查询,并可以高效的返回排序之后的数据。如果我们在处理大数据查询的时候,使用索引就可以令查询对应字段在索引中查询,无序将数据加载到内存中,直接扫描索引然后取索引相对应的数据就行了。
索引类型
默认_id索引
所有mongodb默认都有一个_id字段索引,如果我们不指定_id的值会自动生成一个ObjectId值。
该_id索引是唯一的,并且可以防止客户端对_id字段值相同插入两个。这个index无法被删除
单属性索引
不同于MySQL,Mongodb的索引是有顺序的。但是在单属性索引中索引的顺序并不是十分重要,因为mongodb支持任意顺序遍历单属性索引。
创建一个collection:
{
"_id": ObjectId("570c04a4ad233577f97dc459"),
"score": 1034,
"location": { state: "NY", city: "New York" }
}
然后创建一个单属性索引,在collection的score field上创建一个ascending索引:
db.records.createIndex( { score: 1 } )
通过该索引查询的时候是通过:
db.records.find( { score: 2 } )
db.records.find( { score: { $gt: 10 } } )
由于mongodb支持顺序查找,所以对于单属性查询来说以下查询语句都是可以满足使用index查询的:
db.records.find().sort( { score: 1 } )
db.records.find().sort( { score: -1 } )
db.records.find({score:{$lte:100}}).sort( { score: -1 } )
复合索引
Mongodb 支持对多个 field 建立索引,称之为 compound index。而索引 中 field 的顺序对索引的性能有至关重要的影响,比如上图中索引 {userid:1, score:-1} 首先根据 userid 排序,然后再在每个 userid 中根据 score 排序。
举个例子,首先我们创建一个products collection:
{
"_id": ObjectId(...),
"item": "Banana",
"category": ["food", "produce", "grocery"],
"location": "4th Street Store",
"stock": 4,
"type": "cases"
}
再根据这个collection创建复合索引:
db.products.createIndex( { "item": 1, "stock": 1 } )
通过这个index查询的时候,会首先根据item排序,然后在每个item中继续根据stock进行排序。
但是,使用复合索引需要满足prefix原则
Index prefix 是指 index fields 的左前缀子集,考虑以下索引:
{ "item": 1, "location": 1, "stock": 1 }
这个索引包含以下 index prefix:
{ item: 1 }
{ item: 1, location: 1 }
所以只要语句满足 index prefix 原则都是可以支持使用 compound index 的:
db.products.find( { item: "Banana" } )
db.products.find( { item: "Banana",location:"4th Street Store"} )
db.products.find( { item: "Banana",location:"4th Street Store",stock:4})
复合索引并不像单属性索引呢样对于sort的顺序无关,也就是说sort的顺序必须呀呵创建索引的顺序是“一致”的,具体的规则如下:
实际上还有多键索引、地理空间索引、文本索引、哈希码索引等,但比较常见的或者一般的开发环境中用的最多也就是介绍的几种
建立正确的索引
索引的作用就像是查字典一样,能帮助我们限制数据的选择范围,进一步减少数据库查询的时间和资源。所以我们如果通过复合查询额时候,需要将多个field的顺序考虑禽畜,因为如果第一个field可以迅速缩小数据的查找范围,那么后续的field匹配的行就会变少很多。
-------------------------------------------
个性签名:一名会音乐、爱健身的不合格程序员
可以Follow博主的Github哦(っ•̀ω•́)っ✎⁾⁾