MongoDB索引与优化详解

在MongoDB中经过创建索引能够进行高效的查询,若是没有索引MongoDB将会扫描整个集合与查询的条件进行匹配,这对于性能会形成很大的消耗。

技术博客: Node.js技术栈git

快速导航

面试指南

  • 生产环境如何正确建立索引? ,参考:#

Mongodb索引类型

MongoDB提供了不一样的索引类型支持在不一样的业务场景进行查询

1. _id索引

绝大多数集合默认创建索引,对于每一个插入的数据,MongoDB都会生成一条惟一的_id字段。

例如新建立一个集合时github

db.demo_admin2.insert({x:1})
db.demo_admin2.getIndexes() # 查看集合索引,可看到_id索引

2. 单键索引

是最普通的索引,单键索引不会自动建立

例如一条记录形式为:{x:1,y:2,z:3},只要在x字段上创建索引以后,就能够用x为条件进行查询面试

db.demo_admin2.ensureIndex({x:1}) # 建立索引
db.demo_admin2.find({x:1}); # 使用索引查询

3. 多键索引

多键索引与单键索引区别在于多键索引的值具备多个记录,是一个数组
db.demo_admin2.insert({x:[1,2,3,4]})

4. 复合索引

当查询条件为多个时,须要创建复合索引

插入记录{'x':1,'y':2,'z':3}mongodb

db.demo_admin2.insert({'x':1,'y':2,'z':3});

建立索引shell

db.demo_3.ensureIndex({x:1,y:1}) # 1升序,-1降序

使用{x:1,y:1}做为条件进行查询数据库

db.demo_admin2.find({x:1,y:2})

5. 过时索引

指在一段时间后会过时的索引,此索引过一段时间会过时,索引过时后,相应的数据会被删除,适合存储一些在一段时间以后会失效的数据,好比用户登陆信息,这样就不须要用到session了。

5.1 建立过时索引数组

创建索引的时候须要多用一个参数,指定索引的有效时间——expireAfterSeconds,单位为秒

以下示例为time字段建立过时索引session

db.demo_3.ensureIndex({time:1},{expireAfterSeconds:10})

5.2 过时索引限制性能

  • 过时索引字段值必须是指定的时间类型,必须是ISODate或ISODate数组,不能使用时间戳,不然不能被自动删除。
  • 若是指定了ISODate数组,则按照最小的时间进行删除。 过时索引不能是复合索引。
  • 删除时间不是精确的,删除过程是由后台程序每60s跑一次,并且删除也须要一些时间,因此存在偏差。
db.demo_3.ensureIndex({time:1},{expireAfterSeconds:30}
db.demo_3.insert({time:new Date()});

6. 全文索引

在mongodb中每一个集合只容许建立一个索引,所以不用担忧存在多个索引形成冲突的问题。

6.1 全文索引建立测试

全文索引建立方法与建立单键索引、复合索引相似。value换成'text',$**匹配集合下全部

为一个字段建立全文索引

db.articles.ensureIndex({key:"text"})

为多个字段建立全文索引

db.articles.ensureIndex({key_1:"text"},{key_2:"text"})

为集合中全部的字段建立全文索引

db.articles.ensureIndex({"$**":"text"})

6.2 实例

创建索引

db.article.ensureIndex({"article":"text"})
db.articles.find({$text:{$search:"coffee"}})
db.articles.find({$text:{$search:"aa bb cc"}}) # 包含aa或bb或cc的数据
db.articles.find({$text:{$search:"aa bb -cc"}}) # 同时包含aa、bb且不包含cc的数据
db.articles.find({$text:{$search:"\"aa\" \"bb\" \"cc\""}})# 同时包含aa、bb、cc的数据(用""包裹起来,引号须要用反斜杠\转义)

6.3 mongodb类似度查询

$meta操做符:{score:{$meta:'textScore'}}

查询结果的类似度,搜索出的结果会多出一个score字段,这个得分越高,相关度越高。

db.article.find({$text:{$search:"aa bb ff"}},{score:{$meta:"textScore"}})

加上.sort方法可排序

db.article.find({$text:{$search:"aa bb ff"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}})

6.4 全局索引的限制

  1. 每次查询,只能指定一个$text查询
  2. $text查询不能出如今$nor查询中
  3. 查询中若是包含了$text, hint再也不起做用
  4. MongoDB全文索引还不支持中文

7.地理位置索引

  • 2d索引,用于存储和查找平面上的点
  • 2dsphere索引,用于存储和查找球面上的点

索引属性

1.索引属性name

MongoDB会自动的建立,规则是key_1 或者 key_-1 1或者-1表明排序方向,通常影响不大,长度通常有限制125字节
db.collection.ensureIndex({indexValue},{name: key})

为了见名知意咱们能够本身来命名

db.demo_3.ensureIndex({x:1,y:1,z:1,n:1},{name:'xyz-name'});

删除索引

db.demo_3.dropIndex(indexName)

2. 索引属性unique惟一性指定

相似关系型数据库字段的惟一约束
db.demo_3.ensureIndex({m:1,n:1},{unique:true})

索引实例测试

创建500万条数据,分别用来测试创建索引和未创建索引的差异,只有在大量数据下才有效果,如下的示例中的时间消耗值,各电脑配置的不一样在不一样电脑上测试也会有不一样的差异。
  • 创建测试数据
> for(var i=0; i<5000000; i++) db.demo_user.insert({id: i})
WriteResult({ "nInserted" : 1 })
  • 未创建索引状况数据查询
在未创建索引的状况下,执行数据查询的时间消耗在6秒多。

图片描述

  • 创建索引状况查询数据
db.getCollection('demo_user').ensureIndex({"id": 1}) # 创建索引

下图为创建索引的状况,在数据查询中仅用了0.001秒,可见创建索引的重要的性。

图片描述

索引致使的库级锁

这是一个很坑爹的事情,MongoDB没有像MySql、Oracle拥有行级粒度锁概念,在MongoDB中只有库级粒度锁概念,意味这当你在生产环境中不当心触发了一个写锁的操做时其它的业务也会受影响。

MongoDB中创建索引就是一个触发写锁的过程,一般数据量越大创建的索引占用的写锁时间就会越长,MongoDB中创建索引的两种方式。

  • 前台建立(错误)

    如下为前台创建索引演示能够看到在执行建立索引命令以后,新打开一个终端查询另外一张表一直处于等待状态,直到建立索引完成才返回数据。

db.getCollection('demo_user').ensureIndex({"id": 1}) # 创建索引

图片描述

  • 后台建立(推荐)

基于后台建立索引的方式在执行建立索引命令以后,新开一个终端查询另外一个集合中的数据能够当即获得返回。

db.getCollection('demo_user').ensureIndex({"id": 1}, {background: 1}) # 创建索引

图片描述

做者:五月君
连接:https://www.imooc.com/article...
来源:首发慕课网
Github: Node.js技术栈

推荐阅读

相关文章
相关标签/搜索