返回目录

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

创建索引

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. Handlebars模板引擎之上手

    handlebars Handlebars,一个JavaScript模板引擎,是基于Mustache的扩展.模板引擎的都存在一个上下文环境,这是它的作用区间. 需求:基本使用 需要的库 <scr ...

  2. Android Monkey压力测试介绍

    monkey:通过Monkey程序模拟用户触摸屏幕.滑动Trackball. 按键等操作来对设备上的程序进行压力测试,检测程序多久的时间会发生异常. Monkey的构架 Monkey的参数 Monke ...

  3. JS中的作用域链

    在js中数据的声明方式有两种: 1.用var声明,例如:var num = 10: 2.直接声明,例如:num = 10: 两种声明方式在某些情况下是有区别的: var data = 10; func ...

  4. 每天一个Linux命令(23)--linux 目录结构(一)

    对于每一个Linux 学习者来说,了解 Linux 文件系统的目录结构,是学好Linux 的至关重要的一步,深入了解Linux 文件目录结构的标准和每个目录的详细功能,对于我们用好Linux 系统至关 ...

  5. wemall app商城源码Android之Native(原生)支付模式一demo

    wemall-mobile是基于WeMall的Android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.本文分享Native(原生)支付模式一demo,供技术 ...

  6. mongoDB & Nodejs 访问mongoDB (二)

    非常详细的文档http://mongodb.github.io/node-mongodb-native/2.2/quick-start/quick-start/ 连接数据库 安装express 和 m ...

  7. 【前端】ACE Editor 简易使用示例

    身为一个早已退役的Oier,当然忘不了当年一个个OJ页面上的代码显示和代码编辑器. 其中,洛谷使用的ACE Editor就是之一,非常的简洁美观.以及实际上在前端页面上搭建一个ACE Editor也是 ...

  8. CAEmitterLayer 粒子效果(发射器)

    //创建Layer CAEmitterLayer *emitterLayer = [CAEmitterLayer layer]; //边框 emitterLayer.borderWidth = 1.0 ...

  9. Docker存储驱动之总览

    简介 本文会介绍Docker存储驱动的特性,别列出现在已经支持的存储驱动,最后,会介绍如果选型适合你的存储驱动. 可插拔的存储驱动架构 Docker的存储驱动架构是可插拔的,可以让你很方便的将适合你环 ...

  10. python 接口自动化测试--代码实现(八)

    用例读入数据库: #! /usr/bin/python # coding:utf-8 import sys,os from Engine import DataEngine reload(sys) s ...