MongoDB 索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
createIndex() 方法
MongoDB使用 createIndex() 方法来创建索引。
基本语法格式如下所示:
db.集合名称.createIndex(keys, options)
语法中:
Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。
options下需要掌握的参数
Parameter Type Description
background Boolean 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。
unique Boolean 建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
name string 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDups Boolean 在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparse Boolean 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSeconds integer 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
createIndex() 方法中也可以设置使用多个字段创建索引(关系型数据库中称作联合索引)。
_id索引
单键索引
db.集合名称.createIndex({"title":1})
删除索引
db.集合名称.dropIndex("IndexName")
db.集合名称.dropIndexes()
复合索引
db.集合名称.createIndex({"title":1,"description":-1})
索引数组
在数组中创建索引,需要对数组中的每个字段依次建立索引。
db.集合名称.createIndex({"tags":1})
索引子文档
假设我们需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。 为子文档的三个字段创建索引
db.集合名称.createIndex({"address.city":1,"address.state":1,"address.pincode":1})
全文索引
全文检索对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。 MongoDB 在 2.6 版本以后是默认开启全文检索的,如果你使用之前的版本,你需要使用以下代码来启用全文检索:
db.adminCommand({setParameter:true,textSearchEnabled:true})
创建全文索引
db.集合名称.ensureIndex({key:"text"})
使用全文索引
db.集合名称.find({$text:{$search:"搜索内容"}})
在后台创建索引:
db.集合名称.createIndex({索引字段: 1, 索引字段: 1}, {background: true})
唯一索引:
对字段设置唯一索引时,可以保证字段都是唯一性
语法:
db.集合名称.createIndex({field1:boolean, field2:boolean },{unique: true})
(1)新建唯一索引
例子:
db.集合名称.createIndex({onumber:1},{unique:true})
结果: 我们创建了onumber为唯一索引 当我们插入相同的onumber时,会新增失败
(2)对文档中已经存在的相同的字段新建唯一索引,能否成功呢?
我们文档中已经有数据时,我们新建唯一索引
例子:
db.集合名称.createIndex({onumber:1},{unique:true})
我们集合中的onumber字段值已经有重复,所以会导致创建唯一性索引失败
唯一索引不能够创建在具有重复值的键上,如果你一定要在这样的键上创建,使用dropDups参数,系统对重复值的键上只保留第一条记录,剩下的记录会被删除
例子:
db.集合名称.createIndex({onumber:1},{unique:true,dropDups:true})
设置索引的名称
我们之前在创建索引时,没指定索引名称,MongoDB会生成一个默认的索引名称,我们可以通过name参数来指定我们新建索引的名称
语法:
db.集合名称.createIndex({field1:boolean,field2:boolean },{name: "index_name"})
例子:
db.集合名称.createIndex({onumber:1},{name:"index_onumber"})
查看某集合下的索引:
db.集合名称.getIndexes()
sparse(稀疏索引)
MongoDB是无结构型的NoSQL,同一个集合中的每条文档可以包含某个键,也可以不包含,为了达到如果文档中包含索引键,索引键的值必须唯一,如果不包含索引键那么不用校验唯一的效果,可以在创建索引时使用sparse: true, 也就是稀疏索引。
db.集合名称.createIndex({"Key": 1}, {"unique": true, "sparse": true})
稀疏索引:对不存在的键就不进行索引,也就是该文档上没有建立索引,索引条目中也不包含 索引键为null的索引条目,所以再次插入不包含索引键的文档不会报错,直接插入。注意:稀疏索引不光和唯一索引配合使用,也可以单独使用
TTL日期索引
TTL索引是让文档的某个日期时间满足条件的时候自动删除文档,这是一种特殊的索引,这种索引不是为了提高查询速度的,TTL索引类似于缓存,缓存时间到了就过期了,就要被删除了 expireAfterSeconds: 文档生存的时间,单位是秒,索引键是日期类型的 如果当期时间大于索引键的时间加上缓存时间就会删除该文档
db.集合名称.ensureIndex({"createTime: 1}, {"expireAfterSeconds": 60})
db.集合名称.insert( {"expireTime": new Date('9 22, 2018 23:00:00'), name:'李四'} )
TTL索引是单字段索引,混合索引不支持TTL,并且也会忽略expireAfterSeconds属性
在_id 主键上不能建立TTL索引
在capped collection中不能建立TTL索引,因为MongoDB不能从capped collection中删除文档
你不能在已有索引的字段上再创建TTL索引了,如果你想把非TTL索引改为TTL索引,那就只能删除重建索引了
为了验证我们使用使用了索引,可以使用 explain 命令
db.集合名称.find({Key:"value"}).explain()
强制索引
我们在对MongoDB查询时,可以使用hint强制用某个索引
语法:
db.集合名称.find().hint(“index_name”) 例子:
db.集合名称.find({onumber:1}).hint("onumber_1")
我们强制使用onumber 字段索引名称为onumber_1的索引
MongoDB的查询优化器非常智能,会替你选择该用哪个索引,多数情况下不需要指定的。
查看集合的大小
db.集合名称.totalIndexSize()
MongoDB 索引限制
额外开销 每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。所以,如果你很少对集合进行读取操作,建议不使用索引。
内存(RAM)使用 由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。 如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。
查询限制 索引不能被以下的查询使用: 正则表达式及非操作符,如 $nin, $not, 等。 算术运算符,如 $mod, 等。
索引键限制 从2.6版本开始,如果现有的索引字段的值超过索引键的限制,MongoDB中不会创建索引。
插入文档超过索引键限制 如果文档的索引字段值超过了索引键的限制,MongoDB不会将任何文档转换成索引的集合。
最大范围 集合中索引不能超过64个 索引名的长度不能超过128个字符 一个复合索引最多可以有31个字段