MongoDB基础教程系列--第六篇 MongoDB 索引
使用索引可以大大提高文档的查询效率。如果没有索引,会遍历集合中所有文档,才能找到匹配查询语句的文档。这样遍历集合中整个文档的方式是非常耗时的,特别是处理大数据时,耗时几十秒甚至几分钟都是有可能的。
创建索引
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 索引的更多相关文章
- MongoDB基础教程系列--第七篇 MongoDB 聚合管道
在讲解聚合管道(Aggregation Pipeline)之前,我们先介绍一下 MongoDB 的聚合功能,聚合操作主要用于对数据的批量处理,往往将记录按条件分组以后,然后再进行一系列操作,例如,求最 ...
- MongoDB基础教程系列--第三篇 MongoDB基本操作(二)
1.集合操作 1.1.创建集合 MongoDB 用 db.createCollection(name, options) 方法创建集合. 格式 db.createCollection(name, op ...
- MongoDB基础教程系列--第四篇 MongoDB 查询文档
查询文档 查询文档可以用 find() 方法查询全部文档,可以用 findOne() 查询第一个文档,当然还可以根据 条件操作符 和 $type操作符 查询满足条件的文档. find() 和 find ...
- MongoDB基础教程系列--第五篇 MongoDB 映射与限制记录
上一篇提到的 find() 的方法,细心的伙伴会发现查询的结果都是显示了集合中全部的字段,实际应用中,显然是不够用的.那么有没有办法指定特定的字段显示出文档呢?答案是肯定的,MongoDB 中用映射实 ...
- MongoDB基础教程系列--第八篇 MongoDB 副本集实现复制功能
为什么用复制 为什么要使用复制呢?如果我们的数据库只存在于一台服务器,若这台服务器宕机了,那对于我们数据将会是灾难,当然这只是其中一个原因,若数据量非常大,读写操作势必会影响数据库的性能,这时候复制就 ...
- MongoDB基础教程系列--未完待续
最近对 MongoDB 产生兴趣,在网上找的大部分都是 2.X 版本,由于 2.X 与 3.X 差别还是很大的,所以自己参考官网,写了本系列.MongoDB 的知识还是很多的,本系列会持续更新,本文作 ...
- MongoDB基础教程系列--目录结构
最近对 MongoDB 产生兴趣,在网上找的大部分都是 2.X 版本,由于 2.X 与 3.X 差别还是很大的,所以自己参考官网,写了本系列.MongoDB 的知识还是很多的,本系列会持续更新,本文作 ...
- MongoDB基础教程系列--第一篇 进入MongoDB世界
1.什么是MongoDB MongoDB是跨平台的.一个基于分布式文件存储的数据库.由C++语言编写.用它创建的数据库具备性能高.可用性强.易于扩展等特点.MongoDB将数据存储为一个文档,数据结构 ...
- MongoDB基础教程系列--第二篇 MongoDB基本操作(一)
1.安装环境 在官网上下载MongoDB的最新版本,根据自身Windows版本下载正确的MongoDB版本.下载后,双击32位或者64位.msi文件,按操作提示安装就可以了. 说明: 32 位版本的 ...
随机推荐
- Keepalived + HAProxy 搭建【第二篇】Keepalived 安装与配置
第一步:准备 1. 简介 本文搭建的是利用 Keepalived 实现 HAProxy 的热备方案,即两台主机上的 HAProxy 实例同时运行,其中全总较高的实例为 MASTER,MASTER出现异 ...
- 解决clipboard手机端无法复制的一种思路
最近,做了一个切图的小项目 主要内容是微信号的推广页面,上面会有精美的图片和微信号:) 点击按钮,会复制到粘贴板上,自己去微信里面粘贴搜索:),懒人会进行一系列复杂操作么,不看好 首先,百度了一下,看 ...
- call by value or reference ?
Java中参数传递是传值还是传引用呢?很多人遇到这个问题都会马上给你抛出这个例子: class Entry{ Integer value; public Entry(Integer v){ this. ...
- Django之Model世界
Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数 ...
- TP框架 基础1
php框架 一.真实项目开发步骤: 多人同时开发项目,协作开发项目.分工合理.效率有提高(代码风格不一样.分工不好) 测试阶段 上线运行 对项目进行维护.修改.升级(单个人维护项目,十分困难,代码风格 ...
- Struts2学习笔记②
之前在跟着老师们做项目的时候经常会烦恼Struts.xml怎么配置,老师也没讲太清楚,都是说很简单,但是不懂的人就是太难了!哈哈,万事还是要靠自己的! struts.xml今天又看了几个小时的书,也跟 ...
- 1295: [SCOI2009]最长距离
1295: [SCOI2009]最长距离 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 960 Solved: 498[Submit][Status ...
- 面向对象的全套“企业微信”api接口的代码实现,网上太多“面向过程”微信api接口的代码,这个开源给需要的人用
有段时间没有写文章了. 一直以来,微信的热门是看得到的,很多人都需要与微信的api对接. 今天我这里就分享全套的企业微信api接口的代码. 关于微信api,网上已经有很多实现的了. 但是我今天之所以还 ...
- i++和++i 的学习
在<<C++ Primer>> 第四版 5.5中讲解到: ++i:返回操作之后的结果,且是个左值. i++:返回操作之前的结果,且是有右值. // 2_3.cpp : 定义控制 ...
- ThinkPhp框架:验证码功能
Think\Verify类可以支持验证码的生成和验证功能. 为了显示这个验证码功能,第一要有控制器,再就是有方法,然后是显示的页面. 一.最简单的方式生成验证码 (1)我们还是继续在那个控制器编写方法 ...