简介
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。这种扫描全集合的查询效率是非常低的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。
建立索引后,mongoDB会额外存储一份按照字符升序/降序排序的索引数据,索引结构通常采用类似btree的结构持久化存储,以保证从索引里快速找出某个值的对应的位置信息,然后根据位置信息就能读取出对应的文档
创建索引
语法:
db.collection.createIndex(<keys>,<options>);
or
db.collection.ensureIndex(<keys>,<options>);
下面有一个集合:
我现在对name字段创建索引
# 字段后面是排序规则,1是升序,-1降序
db.users.ensureIndex({'name':1});
创建索引的常用参数:(较为重要的是background和unique)
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。 |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name | string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
dropDups | Boolean | 3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false. |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 |
v | index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language. |
举例:
db.users.ensureIndex({'name':1},{'background':true,'unique':false});
查询索引
语法:
db.collection.getIndexes();
or
db.collection.getIndexSpecs();
查询集合中哪些字段有索引
db.collection.getIndexKeys();
查询索引占用空间:
db.collection.totalIndexSize();
该方法可以传入参数,来显示全部索引的占用空间
db.collection.totalIndexSize(1);
删除索引
删除指定索引语法:
db.collection.dropIndex('indexName');
删除自己创建的所有索引:
db.collection.dropIndexes();
重建索引
db.collection.reIndex()
索引类型
mongodb支持多种类型索引,包括单字段索引、复合索引、多key索引、文本索引等,每种索引类型有不同使用场合。
单字段索引
db.users.ensureIndex({'name':1});
创建索引后,我们可以分析查询:
db.users.find({'name':'n1'}).explain();
交叉索引
为一个集合的多个字段分别建立索引,在查询的时候通过多个字段作为查询条件,这种情况成为交叉索引。
交叉索引的查询效率较低,在使用时,在查询使用到多个字段的时候,尽量使用复合索引,而不是交叉索引。
复合索引
复合索引:它针对多个字段联合创建索引,先按第一个字段排序,第一个字段相同的文档按第二个字段排序,依次类推,如下针对age,name这两个字段创建一个1复合索引。
db.users.createIndex({name':1,'age':1});
db.users.find({'name':'wj','age':{'$lt':2}}).explain();
使用了复合索引:
应用索引的最左前缀规则:如复合索引创建在{'name':1,'age':1}两个字段上,查询条件为{'name':'xxx'}或{'name':'xxx','age':xxxx}或{'age':xxxx,'name':'xxx'},都会使用复合索引,只有{'age':xxx}不会使用复合索引。
多key索引
当索引的字段为数组时,创建出的索引称为多key索引,多key索引会为数组中的每一个元素建立一个索引。
db.users.update({},{'$set':{'courses':['spring','dubbo']}},false,true);
#创建多key索引
db.users.createIndex({'courses':1})
#查看执行计划
db.users.find({'courses':'dubbo'}).explain();
索引特性
唯一索引
保证索引对应的字段不会出现相同的值,比如_id就是唯一索引。如果插入相同的值,则会抛出异常。
#唯一索引的创建
db.stu.createIndex({'name':1},{'unique':true});
部分索引
只针对符合某个特定条件的文档建立索引,3.2版本才支持该特性。
MongoDB部分索引只为那些在一个集合中,满足指定筛选条件的文档创建索引。由于部分索引是一个集合文档的一个子集,因此部分索引具有较低的存储需求,并降低了索引创建和维护的性能成本。部分索引通过指定过滤条件来创建,可以为mongodb支持的所有索引类型使用部分索引。
简单来说:部分索引就是带有过滤条件的索引,即索引只存在与某些文档之上。
db.users.createIndex({'name':1},{'partialFilterExpression':{'age':{'$lte':20}}});
#查看执行计划
db.users.find({'name':'n1','age':19}).explain();
#查看执行计划
db.users.find({'name':'n1','age':30}).explain();
注意:部分索引只为集合中那些满足指定筛选条件的文档创建索引。如果你指定的partialFilterExpression和唯一约束,那么唯一性玉树只适用于满足筛选条件的文档。具有唯一约束的部分索引不会阻止不符合唯一约束且不符合筛选过滤条件的文档的插入。
索引覆盖查询
覆盖查询是以下的查询:
- 所有的查询字段是索引的一部分
- 所有的查询返回字段都在索引中
由于所有出现在查询中的字段是索引的一部分,mongoDB无需在整个数据文档中检索匹配查询条件和返回使用相同索引的查询结果。
由于索引存在内存中,从索引中获取数据比通过扫描文档读取数据快的多。
db.users.find({'name':'n1','age':19},{'name':1}).explain();
索引注意事项
- 当集合中记录较少,一两千甚至几百条,没有必要建立索引,得不偿失。
- 当索引的选择性较低(索引选择性 = 不重复索引值/总记录数)
- 很少对集合进行读取操作,不建议创建索引。
- 索引的大小不应该超过内存限制
索引不能被以下查询使用:
- 正则表达式(最左匹配除外)及非操作符如$nin,$not
- 算术运算符,如$mod
强制约束:
- 集合中索引不能超过64个
- 索引名长度不能超过128字符
- 一个复合索引最多可以有31字段