初识 MongoDB 中的索引

索引就像图书的目录一样,可以让我们快速定位到需要的内容,关系型数据库中有索引,NoSQL 中当然也有,本文我们就先来简单介绍下 MongoDB 中的索引。

索引创建

默认情况下,集合中的 _id 字段就是索引,我们可以通过 getIndexes() 方法来查看一个集合中的索引:

1
db.sang_collect.getIndexes()

结果如下:

1
2
3
4
5
6
7
8
9
10
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "sang.sang_collect"
}
]

我们看到这里只有一个索引,就是 _id

现在我的集合中有 10000 个文档,我想要查询 x 为 1 的文档,我的查询操作如下:

1
db.sang_collect.find({x:1})

这种查询默认情况下会做全表扫描,我们可以用上篇文章介绍的 explain() 来查看一下查询计划,如下:

1
db.sang_collect.find({x:1}).explain("executionStats")

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"queryPlanner" : {
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 15,
"totalKeysExamined" : 0,
"totalDocsExamined" : 10000,
"executionStages" : {
"stage" : "COLLSCAN",
"filter" : {
"x" : {
"$eq" : 1.0
}
},
"nReturned" : 1,
"executionTimeMillisEstimate" : 29,
"works" : 10002,
"advanced" : 1,
"needTime" : 10000,
"needYield" : 0,
"saveState" : 78,
"restoreState" : 78,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 10000
}
},
"serverInfo" : {
},
"ok" : 1.0
}

结果比较长,我摘取了关键的一部分。我们可以看到查询方式是全表扫描,一共扫描了 10000 个文档才查出来我要的结果。实际上我要的文档就排第二个,但是系统不知道这个集合中一共有多少个 x 为 1 的文档,所以会把全表扫描完,这种方式当然很低效,但是如果我加上 limit,如下:

1
db.sang_collect.find({x:1}).limit(1)

此时再看查询计划发现只扫描了两个文档就有结果了,但是如果我要查询 x 为 9999 的记录,那还是得把全表扫描一遍,此时,我们就可以给该字段建立索引,索引建立方式如下:

1
db.sang_collect.ensureIndex({x:1})

1 表示升序,-1 表示降序。当我们给 x 字段建立索引之后,再根据 x 字段去查询,速度就非常快了,我们看下面这个查询操作的执行计划:

1
db.sang_collect.find({x:9999}).explain("executionStats")

这个查询计划过长我就不贴出来了,我们可以重点关注查询要耗费的时间大幅度下降。

此时调用 getIndexes() 方法可以看到我们刚刚创建的索引,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "sang.sang_collect"
},
{
"v" : 2,
"key" : {
"x" : 1.0
},
"name" : "x_1",
"ns" : "sang.sang_collect"
}
]

我们看到每个索引都有一个名字,默认的索引名字为 字段名_排序值,当然我们也可以在创建索引时自定义索引名字,如下:

1
db.sang_collect.ensureIndex({x:1},{name:"myfirstindex"})

此时创建好的索引如下:

1
2
3
4
5
6
7
8
{
"v" : 2,
"key" : {
"x" : 1.0
},
"name" : "myfirstindex",
"ns" : "sang.sang_collect"
}

当然索引在创建的过程中还有许多其他可选参数,如下:

1
db.sang_collect.ensureIndex({x:1},{name:"myfirstindex",dropDups:true,background:true,unique:true,sparse:true,v:1,weights:99999})

关于这里的参数,我说一下:

  1. name 表示索引的名称
  2. dropDups 表示创建唯一性索引时如果出现重复,则将重复的删除,只保留第一个
  3. background 是否在后台创建索引,在后台创建索引不影响数据库当前的操作,默认为 false
  4. unique 是否创建唯一索引,默认 false
  5. sparse 对文档中不存在的字段是否不起用索引,默认 false
  6. v 表示索引的版本号,默认为 2
  7. weights 表示索引的权重

此时创建好的索引如下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"v" : 1,
"unique" : true,
"key" : {
"x" : 1.0
},
"name" : "myfirstindex",
"ns" : "sang.sang_collect",
"background" : true,
"sparse" : true,
"weights" : 99999.0
}

查看索引

上文我们介绍了 getIndexes() 可以用来查看索引,我们还可以通过 totalIndexSize() 来查看索引的大小,如下:

1
db.sang_collect.totalIndexSize()

删除索引

我们可以按名称删除索引,如下:

1
db.sang_collect.dropIndex("xIndex")

表示删除一个名为xIndex的索引,当然我们也可以删除所有索引,如下:

1
db.sang_collect.dropIndexes()

总结

索引是个好东西,可以有效的提高查询速度,但是索引会降低插入、更新和删除的速度,因为这些操作不仅要更新文档,还要更新索引,MongoDB 限制每个集合上最多有 64 个索引,我们在创建索引时要仔细斟酌索引的字段。

好了,MongoDB 中的索引入门我们就说到这里,小伙伴们有问题欢迎留言讨论。

参考资料:

  1. 《MongoDB权威指南第2版》

MongoDB学习笔记(六)的更多相关文章

  1. MongoDB学习笔记六:进阶指南

    [数据库命令]『命令的工作原理』MongoDB中的命令其实是作为一种特殊类型的查询来实现的,这些查询针对$cmd集合来执行.runCommand仅仅是接受命令文档,执行等价查询,因此,> db. ...

  2. MongoDB学习笔记六—查询下

    查询内嵌文档 数据准备 > db.blog.find().pretty() { "_id" : ObjectId("585694e4c5b0525a48a441b5 ...

  3. MongoDB学习笔记(六) MongoDB索引用法和效率分析

    MongoDB中的索引其实类似于关系型数据库,都是为了提高查询和排序的效率的,并且实现原理也基本一致.由于集合中的键(字段)可以是普通数据类型,也可以是子文档.MongoDB可以在各种类型的键上创建索 ...

  4. MongoDB学习笔记(转)

    MongoDB学习笔记(一) MongoDB介绍及安装MongoDB学习笔记(二) 通过samus驱动实现基本数据操作MongoDB学习笔记(三) 在MVC模式下通过Jqgrid表格操作MongoDB ...

  5. MongoDB学习笔记(六)--复制集+sharding分片 && 总结

    复制集+sharding分片                                                               背景 主机 IP 服务及端口 Server A ...

  6. MongoDB学习笔记(五)--复制集 && sharding分片

    主从复制                                                                                       主从节点开启 主节 ...

  7. MongoDB学习笔记:快速入门

    MongoDB学习笔记:快速入门   一.MongoDB 简介 MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统.在高负载的情况下,添加更多的节点,可以保证服务器性能.M ...

  8. MongoDB学习笔记系列

    回到占占推荐博客索引 该来的总会来的,Ef,Redis,MVC甚至Sqlserver都有了自己的系列,MongoDB没有理由不去整理一下,这个系列都是平时在项目开发时总结出来的,希望可以为各位一些帮助 ...

  9. PHP操作MongoDB学习笔记

    <?php/*** PHP操作MongoDB学习笔记*///*************************//**   连接MongoDB数据库  **////*************** ...

  10. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

随机推荐

  1. angular获取时间

    获取24小时制的时间<h1> {{time}} </h1> <script> angular.module('app', []) .controller('ctrl ...

  2. SpringBoot结合策略模式实战套路

    1. SpringBoot结合策略模式实战套路 1.1. 前言 我们都知道设计模式好,可以让我们的代码更具可读性,扩展性,易于维护,但大部分程序猿一开始都学过至少一遍设计模式吧,实战中不知用到了几成. ...

  3. 英语chrismatite黄蜡石chrismatite单词

    黄蜡石chrismatite的原岩均为硅质岩,各种原岩受到构造变动.火山活动.热液作用等影响,产生复杂的物理和化学变化,包括重结晶.热变质等,导致矿物成分及结构构造的变化,后受构造变动的影响,岩石露出 ...

  4. 5.如何基于 dubbo 进行服务治理、服务降级、失败重试以及超时重试?

    作者:中华石杉 面试题 如何基于 dubbo 进行服务治理.服务降级.失败重试以及超时重试? 面试官心理分析 服务治理,这个问题如果问你,其实就是看看你有没有服务治理的思想,因为这个是做过复杂微服务的 ...

  5. Codeforces Round #305 (Div. 2)D. Mike and Feet(单调栈)

    题意 n个值代表n个熊的高度 对于size为x的group strength值为这个group(连续的几个熊)中熊的最小的height值 对于x(1<=x<=n) 求出最大的strengt ...

  6. 第18.2节_地址类型与LL层设备过滤

    一.地址类型 二.白名单和Resolving List 三.LL层设备过滤 一.地址类型 学习资料:官方手册 Vol 6: Core System Package [Low Energy Contro ...

  7. springboot+springcloud微服务项目全套资料(笔记+源码+代码)

    最近好几天没有写博客了,由于时间的太忙了,项目要做.各种资格证要考试,实在没有时间写了,今天正好赶上有闲暇的一刻,应许多的爱好者的要求发一份微服务项目的资料,此资料十分完整,且是最新的.希望各位读者能 ...

  8. Python 包:

    分享一波油藏描述方面的Python开源包 前一阵去捷克参加了数学地质年会(IAMG2018),听完汇报,发现在数学地质领域用python的越来越多了,他们的很多成果都是用python做出来的.不管喜不 ...

  9. 【java】[null]的问题

    这么写逻辑就有问题,改成下面的

  10. input type属性为number时,去掉右边的上下箭头

    加上样式: input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; ...