索引
索引能够提升查询的效率。没有索引,MongoDB必须扫描集合中的所有文档,才能找到匹配查询语句的文档。
索引是一种特殊的数据结构,将一小块数据集保存为容易遍历的形式。索引能够存储某种特殊字段或字段集的值,并按照索引指定的方式将字段值进行排序。
然而使用索引也是有代价的:对于添加的每一个索引,每次的插入、更新、删除都将会消耗更多的时间。这是因为当数据发生变动时,数据库不仅要更新文档,还要更新集合上的所有索引。 MongoDB限制每个集合上最多只能由64个索引。
使用索引键对文档进行排序可以提升排序的效率,因为索引键是按照一定顺序排列的,当然必须首先使用索引键进行排序时,索引才有用。
创建索引
db.collection.createIndex( <keys>, <options> )
参数说明:
- keys:希望创建索引的名称及排序方式,1 代表按升序排列;-1 代表按降序排列,格式:{key1:1,key2:-1} 如果是基于多个索引键进行排序时,要特别注意索引的排序方向,相同的排序方向可以提升排序效率,单个键排序时没有此影响
- options可选参数
options可选参数
参数 |
类型 |
描述 |
background |
布尔值 |
在后台构建索引,从而不干扰数据库的其他活动。取值为 true 时,代表在后台构建索引。默认值为 false 默认情况下MongoDB为尽可能快的创建索引,会阻塞索引针对数据库的读操作和写操作直到索引创建完成为止,可以通过设置此参数为true使数据库在创建索引的同事也能够处理数据库的读写操作。另外后台创建索引比前台创建索引要慢得多。 |
unique |
布尔值 |
创建一个唯一的索引,从而当索引键匹配了索引中一个已存在值时,集合不接受文档的插入。取值为 true 代表创建唯一性索引。默认值为 false。 |
name |
字符串 |
索引名称。如果未指定,MongoDB 会结合索引字段名称和排序序号,生成一个索引名称。 |
sparse |
布尔值 |
如果为 true,索引只引用带有指定字段的文档。这些索引占据的空间较小,但在一些情况下的表现也不同(特别是排序)。默认值为 false。 |
expireAfterSeconds |
整型值 |
指定一个秒数值,作为 TTL 来控制 MongoDB 保持集合中文档的时间。 |
weights |
文档 |
数值,范围从 1 到 99, 999。表示就字段相对于其他索引字段的重要性。 |
default_language |
字符串 |
对文本索引而言,用于确定停止词列表,以及词干分析器(stemmer)与断词器(tokenizer)的规则。默认值为 english。 |
language_override |
字符串 |
对文本索引而言,指定了文档所包含的字段名,该语言将覆盖默认语言。默认值为 language。 |
唯一索引
唯一索引可以确保集合中的每一个文档指定的键都有唯一值而符合唯一索引则可以单个键值相同,但是多个键值的组合值必须唯一
db.collection.createIndex({key:1,key1:1},{unique:true})
稀疏索引
稀疏索引会跳过所有不包含被索引键的文档。这个索引之所以称为 "稀疏" 是因为它并不包括集合中的所有文档。与之相反,非稀疏的索引会索引每一篇文档,如果一篇文档不含被索引键则为它存储一个null值。
如果希望针对一个可能存在也可能不存在的字段添加唯一索引时,可以使用unique与sparse组合使用,这样就可以保障在这个字段存在时就是唯一的
当然稀疏索引也不必是唯一的只要去掉unique选项就可以了
db.collection.createIndex({key:1},{sparse:true})
注意:根据是否使用稀疏索引,同一查询的返回结果可能会不同,使用稀疏索引后会过滤掉不含该稀疏索引键值的文档。
TTL索引
TTL索引,time to live index 具有生命周期的索引,这种索引允许为每个文档设置一个过期时间,当超过指定时间后,集合自动清除超时的文档
用来保存一些诸如session会话信息的时候非常有用,或者存储缓存数据使用。但删除会有延时
索引的字段必须是一个日期的 bson 类型
如果要索引的字段已经在其他索引中使用,将不能创建 TTL 索引。否则超时后文档不会被自动清除。
索引不能包含多个字段
固定集合不能创建TTL索引
不能针对已经存在TTL索引更改expireAfterSeconds的值,可以通过删除再创建的方式处理
db.collection.createIndex({key:1},{expireAfterSeconds:seconds})
注意:Mongodb每分钟针对TTL进行一次清理,所以不能以秒为单位设置索引的存活状态,可以使用collMod设置expireAfterSeconds的值
db.runCommand( {"collMod" : <collection> , "expireAfterSeconds" : <value> } )
全文索引
全文索引用于在文档中搜索文本,我们也可以使用正则表达式来查询字符串,但是当文本块比较大的时候,正则表达式搜索会非常慢,而且无法处理语言理解的问题(如 entry 和 entries 应该算是匹配的)。使用全文索引可以非常快地进行文本搜索,就如同内置了多种语言分词机制的支持一样。创建索引的开销都比较大,全文索引的开销更大。创建索引时,需后台或离线创建
地理空间索引
MongoDB支持几种类型的地理空间索引。其中最常用的是 2dsphere 索引(用于地球表面类型的地图)和 2d 索引(用于平面地图和时间连续的数据)
哈希索引
哈希
索引可以支持相等查询,但是
哈希
索引不支持范围查询。您可能无法创建一个带有
哈希
索引键的复合索引或者对
哈希
索引施加唯一性的限制。但是,您可以在同一个键上同时创建一个
哈希
索引和一个递增/递减(例如,非哈希)的索引,这样MongoDB对于范围查询就会自动使用非哈希的索引
局部索引
这是3.2.0版本以后新增的
只会对Collections满足条件partialFilterExpression的文档进行索引
使用该索引,会在一定程度上减少存储空间和创建索引和维护性能降低的成本
db.collection.createIndex(
{ key: 1 },
{ partialFilterExpression: { key1: value } }
)
删除索引
db.collection.dropIndexes()会删除当前集合中的所有索引(_id上的默认索引除外).
db.collection.dropIndex(index)可以根据指定的索引名称或索引文档删除索引(_id上的默认索引除外).
获取索引
db.collection.getIndexes() 可以获取当前集合中所有的索引信息
查询分析
$explain 操作提供的消息包括:查询消息、查询所使用的索引以及其他的统计信息。在分析索引优化方案时,这是一个非常有用的工具。
db.users.find({userName:"user1001"}).explain()
$hint操作符强制索引优化器使用指定的索引运行查询。这尤其适用于测试带有多个索引的查询性能
db.users.find({userName:"user1001"}).hint({userName:1})
注意:
- 如果有一个多键复合索引,如:{a:1,b:1,c:1...z:1}.在MongoDB中实际可以使用{a:1};{a:1,b:1};{a:1,c:1}等一系列索引,而使用{b:1};{b:1,c:1}等作为索引查询时则不会使用到之前创建的索引,因为只有使用索引前缀的查询才会被优化。
- $exists 不会使用索引,$ne虽然使用索引但是必须检查所有的索引条目,跟不使用没什么区别 $not大部分情况下都是使用全表扫描 $nin和$in总是全表扫描 $or 可以对每个字句分别使用索引,因为$or实际是执行两次查询然后进行的结果集合并
- 应该在索引基数比较高的键上建立索引,或至少应该把索引基数较高的键放在复合索引的前面(低基数键的前面)
基数就是集合中某个字段拥有不同值的数量 - 查询得到的结果集在原集合中所占比例越大,索引的速度越慢,因为使用索引是需要进行两次查找的:1.查找索引条目,2.根据索引指针查找对应的文档。而全表扫描只要进行一次查询:查询对应的文档。
一般来说如果查询的结果集占据原集合比例的30%时,就要对比使用索引及全表扫描是的速度进行对比。