返回目录

使用索引可以大大提高文档的查询效率。如果没有索引,会遍历集合中所有文档,才能找到匹配查询语句的文档。这样遍历集合中整个文档的方式是非常耗时的,特别是处理大数据时,耗时几十秒甚至几分钟都是有可能的。

创建索引

MongoDB 中,使用 ensureIndex() 方法创建索引。

格式

db.COLLECTION_NAME.ensureIndex({KEY:1})

其中,KEY表示要创建索引的字段名称,1 表示按升序排列字段值。-1 表示按降序排列。

范例

1、给 user 集合中 name 字段添加索引

>db.user.ensureIndex({"name":1})
>

MongoDB 中用 db.collection.getIndexes() 方法查询集合中所有的索引,我们查询一下 user 中所有的索引。

>db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "liruihuan.user"
},
{
"v" : 2,
"key" : {
"age" : 1
},
"name" : "name_1",
"ns" : "liruihuan.user"
}
]

我们发现 user 中有两个索引,其中索引 "_id_" 是我们创建 user 集合时,MongoDB 自动生成的索引。第二个索引就是我们刚才创建的索引,其中,name 值"name_1"表示索引名称,MongoDB 会自动生成的索引名称。当然,我们也可以自己指定索引的名称。

2、给 user 集合中 age 字段添加索引,并指定索引名称为 "index_age_esc"。

>db.user.ensureIndex({"age":1},{name:"index_age_esc"})
>db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "liruihuan.user"
},
{
"v" : 2,
"key" : {
"age" : 1
},
"name" : "index_age_esc",
"ns" : "liruihuan.user"
}
]

指定索引名称用到的 name 参数,只是 ensureIndex() 方法可接收可选参数的其中一个,下表列出了 ensureIndex() 方法可接收的参数

Parameter Type Description
background 布尔值 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false
unique 布尔值 建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
name 字符串 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDups 布尔值 在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparse 布尔值 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSeconds 整型 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
v 索引版本 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weights 文档(document) 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_language 字符串 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_override 字符串 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

唯一索引

MongoDB和关系型数据库一样都可以建立唯一索引,重复的键值就不能重新插入了,MongoDB 用 unigue 来确定建立的索引是否为唯一索引,true 表示为唯一索引,下面给 user 集合的 name 字段指定唯一索引

>db.user.ensureIndex({"name":1},{unique:true})

> db.user.find()
{ "_id" : ObjectId("58e1d2f0bb1bbc3245fa754b"), "name" : "liruihuan", "age" : 18,"sex":"man" } >db.user.insert({"name":"liruihuan","age":18})
E11000 duplicate key error collection: liruihuan.user index: name_1 dup key: { : \"liruihuan\"

可以看出,创建了唯一索引的字段,是不能再插入 "liruihuan" 的 name 值的。

复合索引

ensureIndex() 方法中你也可以设置使用多个字段创建索引

范例

>db.user.ensureIndex({"name":1,"age":1})
>db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "liruihuan.user"
},
{
"v" : 2,
"key" : {
"name" : 1,
"age" : 1
},
"name" : "name_1_age_1",
"ns" : "liruihuan.user"
}
]

删除索引

MongoDB 用dropIndex() 方法删除索引

格式

db.COLLECTION_NAME.dropIndex()

注:dropIndex() 方法可根据指定的索引名称或索引文档删除索引(_id上的默认索引除外)

范例

我们用两种方式删除掉 user 中 name 字段上的索引

>db.user.dropIndex("name_1")     #根据索引名称删除索引
>db.user.dropIndex({"name":1}) #根据索引文档删除索引

还可以用 dropIndexes() 删除集合中所有索引(_id上的默认索引除外)

>db.user.dropIndexes()

查询分析

查询分析是查询语句性能分析的重要工具。

MongoDB 中查询分析用 explain() 和 hint() 方法

范例

我们向集合 user 中插入20万条数据,利用 explain() 查询建立索引前后,执行时间的比较,来看看建立索引对查询效率的提高程度。

第一步,向 user 中插入20万条数据

>db.user.remove({})
>for(var i = 0; i <200000; i++){db.user.insert({"name":"lrh"+i,"age":18})}

第二步,删除 user 集合中字段 name 上的索引,然后查询 name = "lrh100000",利用explain("executionStats")查询此时执行的时间。说明:MongoDB explain() 方法在3.0以后版本中发生了很大改变,3.0之前版本直接用explain()就可以,不用传参数,如果想详细了解,请访问官网

>db.user.dropIndexes()      #删除所有索引
db.user.find({"name":"lrh100000"}).explain("executionStats")
{
"queryplanner" : {
......
},
"executionStats" : {
"executionTimeMillis" : 109
......
}
}

explain.executionStats.executionTimeMillis:表示查询所用的时间,单位是毫秒。

我们可以清楚的看出,没用索引查询用到的时间是 109 毫秒。

第三步,给 user 集合中 name 字段添加索引,然后再查询同一个条件,看执行查询所用了多久时间。

>db.user.ensureIndex({"name":1})
>db.user.find({"name":"lrh100000"}).explain("executionStats")
{
"queryplanner" : {
"winningPlan" : {
"inputStage" : {
"indexName" : "name_1"
......
}
.......
}
.......
},
"executionStats" : {
"executionTimeMillis" : 1
......
}
}

如果用到了索引,explain() 方法会返回 winningPlan,标识用到的索引名称 indexName

我们可以清楚到处,用了索引,执行时间只有 1 毫秒,可以看出,查询效率的提高可不是一星半点。

注:如果想更详细的了解 explain() 返回的参数,可以去官网看一下

第四步,这一步我们重点看看 hint() 方法的用法。hint() 方法用来强制 MongoDB 使用一个指定的索引。

我们给 user 再添加一个 {"name":1, "age":1},利用 explain() 方法,看一下用到了哪个索引。

>db.user.ensureIndex({"name":1, "age":1})
>db.user.find({"name":"lrh100000"}).explain("executionStats")
{
"queryplanner" : {
"winningPlan" : {
"inputStage" : {
"indexName" : "name_1_age_1"
......
}
.......
}
.......
}
......
}

可以看出,此时用到的索引是 "name_1_age_1",如果我们想用索引 "name_1",就可以用 hint() 方法指定。

>db.user.find({"name":"lrh100000"}).hint({"name":1}).explain("executionStats")
{
"queryplanner" : {
"winningPlan" : {
"inputStage" : {
"indexName" : "name_1"
......
}
.......
}
.......
}
......
}

业精于勤,荒于嬉;行成于思,毁于随。

如果你觉得这篇文章不错或者对你有所帮助,可以通过右侧【打赏】功能,给予博主一点点鼓励和支持

MongoDB基础教程系列--第六篇 MongoDB 索引的更多相关文章

  1. MongoDB基础教程系列--第七篇 MongoDB 聚合管道

    在讲解聚合管道(Aggregation Pipeline)之前,我们先介绍一下 MongoDB 的聚合功能,聚合操作主要用于对数据的批量处理,往往将记录按条件分组以后,然后再进行一系列操作,例如,求最 ...

  2. MongoDB基础教程系列--第三篇 MongoDB基本操作(二)

    1.集合操作 1.1.创建集合 MongoDB 用 db.createCollection(name, options) 方法创建集合. 格式 db.createCollection(name, op ...

  3. MongoDB基础教程系列--第四篇 MongoDB 查询文档

    查询文档 查询文档可以用 find() 方法查询全部文档,可以用 findOne() 查询第一个文档,当然还可以根据 条件操作符 和 $type操作符 查询满足条件的文档. find() 和 find ...

  4. MongoDB基础教程系列--第五篇 MongoDB 映射与限制记录

    上一篇提到的 find() 的方法,细心的伙伴会发现查询的结果都是显示了集合中全部的字段,实际应用中,显然是不够用的.那么有没有办法指定特定的字段显示出文档呢?答案是肯定的,MongoDB 中用映射实 ...

  5. MongoDB基础教程系列--第八篇 MongoDB 副本集实现复制功能

    为什么用复制 为什么要使用复制呢?如果我们的数据库只存在于一台服务器,若这台服务器宕机了,那对于我们数据将会是灾难,当然这只是其中一个原因,若数据量非常大,读写操作势必会影响数据库的性能,这时候复制就 ...

  6. MongoDB基础教程系列--未完待续

    最近对 MongoDB 产生兴趣,在网上找的大部分都是 2.X 版本,由于 2.X 与 3.X 差别还是很大的,所以自己参考官网,写了本系列.MongoDB 的知识还是很多的,本系列会持续更新,本文作 ...

  7. MongoDB基础教程系列--目录结构

    最近对 MongoDB 产生兴趣,在网上找的大部分都是 2.X 版本,由于 2.X 与 3.X 差别还是很大的,所以自己参考官网,写了本系列.MongoDB 的知识还是很多的,本系列会持续更新,本文作 ...

  8. MongoDB基础教程系列--第一篇 进入MongoDB世界

    1.什么是MongoDB MongoDB是跨平台的.一个基于分布式文件存储的数据库.由C++语言编写.用它创建的数据库具备性能高.可用性强.易于扩展等特点.MongoDB将数据存储为一个文档,数据结构 ...

  9. MongoDB基础教程系列--第二篇 MongoDB基本操作(一)

    1.安装环境 在官网上下载MongoDB的最新版本,根据自身Windows版本下载正确的MongoDB版本.下载后,双击32位或者64位.msi文件,按操作提示安装就可以了. 说明: 32 位版本的 ...

随机推荐

  1. awk,sed文本处理案例

    #!/bin/bash ############################################################################# #针对一个多级目录下 ...

  2. 【新建项目&使用viewPager】实现一个Android电子书阅读APP

    本章结尾处已放出应用DEMO,已经实现所有本文及后续文章所述全部功能,大家可以先下载下来玩玩看,欢迎在本文下方评论,小方很需要鼓励支持!!! 新建一个项目 呼-我们即将步入安卓开发之旅了,首先要新建一 ...

  3. 服务器数据库搭建流程(CentOs+mysql)

    前言: 服务器上数据库搭建需要知道Linux系统的版本,以前的Ubuntu14.04直接在终端下输入apt-get install (package)便可方便的下载并安装mysql,但是在centOs ...

  4. js实现ajax的post请求步骤

    post请求步骤与前篇的get请求步骤差别不大,只是增加了 xhr.setRequestHeader("Content-type","application/x-www- ...

  5. Webdriver初探

    1.启动Firefox浏览器失败 package org.coder.demo; import org.openqa.selenium.*; import org.openqa.selenium.We ...

  6. javascript-引用类型--Object类型

    引用类型是一种数据结构,本质是数据和功能的集合.引用类型有时也被称为对象定义,因为它们描述的是一类对象所具有的属性和方法.引用类型相当于java里面的类,javascript虽然是一门面向对象语言,但 ...

  7. border-radius IE8兼容处理

    根据canisue(http://caniuse.com/#search=border-radius),border-radius兼容性如下图所示: 测试代码: <!DOCTYPE html&g ...

  8. java 文件操作(二)---Files和Path

    自从java 7以来,引入了FIles类和Path接口.他们两封装了用户对文件的所有可能的操作,相比于java 1的File类来说,使用起来方便很多.但是其实一些本质的操作还是很类似的.主要需要知道的 ...

  9. 由一个简单需求到Linux环境下的syslog、unix domain socket

    本文记录了因为一个简单的日志需求,继而对linux环境下syslog.rsyslog.unix domain socket的学习.本文关注使用层面,并不涉及rsyslog的实现原理,感兴趣的读者可以参 ...

  10. 读书笔记 effective c++ Item 38 通过组合(composition)为 “has-a”或者“is-implemented-in-terms-of”建模

    1. 什么是组合(composition)? 组合(composition)是一种类型之间的关系,这种关系当一种类型的对象包含另外一种类型的对象时就会产生.举个例子: class Address { ...