一、前言
索引能够提高数据库的查询效率,没有索引的话,查询会进行全表扫描(scan every document in a collection),严重降低了查询效率。默认情况下,Mongo在一个集合(collection)创建时,自动地对集合的_id创建了唯一索引。
二、索引相关概念
1.索引
索引通常能够极大的提高查询的效率
,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。
2.索引的类型
B+ Tree、hash、空间索引、全文索引
MongoDB支持的索引:
单字索引、组合索引(多字段索引)、
多键索引:索引创建在值为键值对上的索引
空间索引:基于位置查找
文本索引:相当于全文索引
hash索引:精确查找,不适用于范围查找
3.索引规则
3.1 查询优化器
Mongo自带了一个查询优化器
会为我们选择最合适的查询方案。
如果一个索引能够精确匹配一个查询,那么查询优化器就会使用这个索引。
(1)如果不能精确匹配呢?可能会有几个索引都适合你的查询,那MongoDB是怎样选择的呢?
- MongoDB的查询计划会
将多个索引并行的去执行
,最先返回第101个结果的就是胜者,其他查询计划都会被终止,执行优胜的查询计划; - 这个查询计划会被缓存,接下来相同的查询条件都会使用它;
(2)何时查询计划缓存才会变呢?
- 在计划评估之后表发生了比较大的数据波动,
查询优化器
就会重新挑选可行的查询计划 - 建立索引时
- 每执行1000次查询之后,
查询优化器
就会重新评估查询计划
3.2 联合索引的优化
当你查询条件的顺序和你索引的顺序不一致
的话,mongo会自动的调整查询顺序,保证你可以使用上索引。
例如:你的查询条件是(a,c,b)但是你的索引是(a,b,c)mongo会自动将你的查询条件调整为abc,寻找最优解。
3.3 最左前缀原则
假定索引(a,b,c) 它可能满足的查询如下:
(1)a
(2)a,b
(3)a,b,c
(4)a,c [该组合只能用a部分]
(5)a, c, b [cb在查询时会被优化换位置]
显然,最左前缀的核心是查询条件字段
必须含有索引第一个字段
最左值尽可能用最精确过滤性最好的值,不要用那种可能会用于范围模糊查询,用于排序的字段
3.4 效率极低的操作符
(1)(where和)exists:这两个操作符,完全不能使用索引
。
(2)(ne和)not:通常来说取反和不等于,可以使用索引,但是效率极低
,不是很有效,往往也会退化成扫描全表。
(3)$nin:不包含
,这个操作符也总是会全表扫描
(4)对于管道中的索引,也很容易出现意外,只有在管道最开始时的match sort可以使用到索引,一旦发生过project投射,group分组,lookup表关联,unwind打散等操作后,就完全无法使用索引。
三、索引操作
3.1 创建索引 createIndex()
MongoDB使用 createIndex()
方法来创建索引。
注意:
在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex()
,之后的版本使用了 db.collection.createIndex() 方法,ensureIndex() 还能用,但只是 createIndex() 的别名。
语法:db.collection.createIndex(keys, options)
createIndex()方法基本语法格式如下所示:
db.collection.createIndex(keys, options)
语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。
MongoDB 支持文档集合中任何字段的索引,在默认情况下,所有集合在 _id 字段上都有一个索引,应用程序和用户可以添加额外的索引来支持重要的查询操作。
对于单字段索引和排序操作,索引键的排序顺序(即升序或降序)无关紧要
,因为 MongoDB 可以在任意方向上遍历索引。
实例一:创建普通单键索引
// 为集合electMeterRealData 创建单键索引
db.electMeterRealData.createIndex({
"deviceId":1},{
background: true})
执行结果:
实例二:创建唯一索引
唯一索引是索引具有的一种属性,让索引具备唯一性
,确保这张表中,该条索引数据不会重复出现。在每一次insert和update操作时,都会进行索引的唯一性校验,保证该索引的字段组合在表中唯一。
// 为集合User 创建唯一索引,索引字段为name
db.User.createIndex({
name: 1},{
unique:true, background: true})
Mongo提供两种建索引的方式foreground和background。
前台操作,它会阻塞用户对数据的读写操作直到index构建完毕;
后台模式,不阻塞数据读写操作,独立的后台线程异步构建索引,此时仍然允许对数据的读写操作。
创建索引时一定要写{background: true}
MongoDB中是只有库级锁的,创建索引时要添加参数{background: true}
实例二:创建多键索引(复合索引)
MongoDB 支持复合索引,其中复合索引结构包含多个字段
复合索引可以支持在多个字段上进行的匹配查询,语法结构如下:
db.collection.createIndex ({ <key1> : <type>, <key2> : <type2>, ...})
需要注意的是,在建立复合索引的时候一定要注意顺序的问题,顺序不同将导致查询的结果也不相同
。
实例:
// 为集合electMeterRealData 创建多键索引
db.electMeterRealData.createIndex({
"deviceId":1,"collectionTime":1},{
background: true})
执行效果: