索引可以用来优化查询,而且在某些特定类型的查询中,索引是必不可少的。为集合选择合适的索引是提高性能的关键。

先来mock数据

for (i = 0; i < 1000000; i++) {
db.users.insert({
"i": i,
"username": "user" + i,
"age": Math.floor(Math.random() * 120),
"created": new Date()
});
}

数据库中会创建一百万条数据,稍微有点慢,需要等会。

我们可以使用explain()函数查看MongoDB在执行查询的过程中所做的事情。执行如下命令,查找用户名为user1000的用户。

db.users.find({username:"user1000"}).explain()

得到结果如下:

{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1000000,
"nscanned" : 1000000,
"nscannedObjectsAllPlans" : 1000000,
"nscannedAllPlans" : 1000000,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 7813,
"nChunkSkips" : 0,
"millis" : 411,
"server" : "user:27017",
"filterSet" : false
}

之后会详细介绍各个字段的意思,现在我们只需要知道,"n"表示查询结果的数量,"nscanned"表示MongoDB在完成这个查询的过程中扫描的文件总数,"millis"表示这个查询耗费的毫秒数。可以看到,为了查找user1000,MongoDB遍历了整个集合,消耗了411毫秒。

为了优化查询,我们可以在查找到一个结果的时候,就结束查询,返回结果。命令如下:

db.users.find({username:"user1000"}).limit(1).explain()

结果如下:

{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1001,
"nscanned" : 1001,
"nscannedObjectsAllPlans" : 1001,
"nscannedAllPlans" : 1001,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 7,
"nChunkSkips" : 0,
"millis" : 1,
"server" : "user:27017",
"filterSet" : false
}

可以看到扫描文档数和消耗时间都变少了很多,但是如果我们要查找user999999,MongoDB还是要遍历集合才能找到。而且随着用户数量的增多,查询会越来越慢。

对于这种情况,创建索引是一个非常好的解决方案:索引可以根据给定的字段组织数据,让MongoDB能够非常快速的找到目标文档。使用如下命令,在username字段上创建一个索引。

db.users.ensureIndex({"username":1})

然后再来执行一下之前执行过的语句

db.users.find({username:"user1000"}).explain()

其结果如下:

{
"cursor" : "BtreeCursor username_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"username" : [
[
"user1000",
"user1000"
]
]
},
"server" : "user:27017",
"filterSet" : false
}

然后你会发现查询变快了很多,几乎是瞬间完成,这就是使用索引的效果。但是索引也是有代价的,对于添加的每一个索引,每次写操作(插入、更新、删除)都将耗费更多的时间。这是因为当数据发生变动时,MongoDB不仅要更新文档,还要更新集合上的所有索引。因此,MongoDB限制每个集合上最多只能有64个索引。通常,在一个特定的集合上,不应该拥有两个以上的索引。

当一个索引建立在多个字段上时,我们称它为复合索引,创建的语句如下:

db.users.ensureIndex({"age":1, "username":1})

如果查询中有多个排序方向或者查询条件中有多个键,复合索引就会非常有用。

MongoDB对这个索引的使用方法取决于查询的类型。下面是三种主要的方式。

第一种:

db.users.find({"age":21}).sort({"username":-1})

这是一个点查询,用于查找单个值(尽管包含这个值的文档是多个)。由于索引中的第二个字段,查询结果已经是有序的了。这种类型的查询是非常高效的。

第二种:

db.users.find({"age":{"$gte":21,"$lte":30}})

这是一个多值查询,查找到多个值相匹配的文档,MongoDB会使用索引中的第一个键“age”得到匹配文档。如果使用“username”做查询,该索引不起作用。

第三种:

db.users.find({"age":{"$gte":21,"$lte":30}}).sort({"username":1})

这也是一个多值查询,与上一个类似,只是这次需要对查询结果进行排序。MongoDB需要在内存中对结果进行排序,不如上一个高效。

删除索引的命令如下:

db.users.dropIndex('age_1_username_1')

删除users集合中名字为'age_1_username_1'的索引。

所有数据库的索引信息都存储在system.indexes集合中,这是一个保留集合,不能在其中插入或者删除文档,只能通过ensureIndex和dropIndex对其进行操作。

使用如下命令可以获取users集合上的索引信息:

db.users.getIndexes()

结果如下:

[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.users"
},
{
"v" : 1,
"key" : {
"username" : 1
},
"name" : "username_1",
"ns" : "test.users"
},
{
"v" : 1,
"key" : {
"age" : 1,
"username" : 1
},
"name" : "age_1_username_1",
"ns" : "test.users"
}
]

集合中的每一个索引都有一个名称,用于唯一标识这个索引,也可以用于服务器端来删除或者操作索引。索引的默认形式是keyname1_dir1_keyname2_dir2_..._keynameN_dirN,其中keynameX是索引的键,dirX是索引的方向(1或者-1)。如果索引中包含两个以上的键,这种命名方式就显得比较笨重了,但是我们可以通过ensureIndex指定索引的名称:

db.users.ensureIndex({"a":1, "b":1, ..., "z":1},...{"name":"test_name"})

另外需要注意索引的名称长度是有限制的,所以新建复杂索引时可能需要自定义索引名称。调用getLastError就可以知道索引是否创建成功,或者失败的原因。

MongoDB的学习--索引的更多相关文章

  1. MongoDB的学习--索引类型和属性(转)

    原文链接:MongoDB的学习--索引类型和属性 索引类型 MongDB的索引分为以下几种类型:单键索引.复合索引.多键索引.地理空间索引.全文本索引和哈希索引 单键索引(Single Field I ...

  2. MongoDB的学习--索引类型和属性

    索引类型 MongDB的索引分为以下几种类型:单键索引.复合索引.多键索引.地理空间索引.全文本索引和哈希索引 单键索引(Single Field Indexes) 在一个键上创建的索引就是单键索引, ...

  3. [转载]MongoDB开发学习(2)索引的基本操作

    索引能够极大的提高查询的效率.在数据库中简历索引必不可少. 在MongoDB中可以很轻松的创建索引. 默认索引_id_ 开启MongoDB服务器,创建数据库cnblogs,创建集合Users .(关于 ...

  4. MongoDB数据模型和索引学习总结

    MongoDB数据模型和索引学习总结 1. MongoDB数据模型: MongoDB数据存储结构: MongoDB针对文档(大文件採用GridFS协议)採用BSON(binary json,採用二进制 ...

  5. NoSQL之【MongoDB】学习(三):配置文件说明

    摘要: 继上一篇NoSQL之[MongoDB]学习(一):安装说明 之后,知道了如何安装和启动MongoDB,现在对启动时指定的配置文件(mongodb.conf)进行说明,详情请见官方. 启动Mon ...

  6. 深入理解MongoDB的复合索引

    更新时间:2018年03月26日 10:17:37   作者:Fundebug    我要评论 对于MongoDB的多键查询,创建复合索引可以有效提高性能.这篇文章主要给大家介绍了关于MongoDB复 ...

  7. MongoDB的学习--explain()和hint()

    Explain 从之前的文章中,我们可以知道explain()能够提供大量与查询相关的信息.对于速度比较慢的查询来说,这是最重要的诊断工具之一.通过查看一个查询的explain()输出信息,可以知道查 ...

  8. mongodb的地理位置索引

    mongoDB支持二维空间索引,使用空间索引,mongoDB支持一种特殊查询,如某地图网站上可以查找离你最近的咖啡厅,银行等信息.这个使用mongoDB的空间索引结合特殊的查询方法很容易实现.前提条件 ...

  9. 双刃剑MongoDB的学习和避坑

    双刃剑MongoDB的学习和避坑 MongoDB 是一把双刃剑,它对数据结构的要求并不高.数据通过key-value的形式存储,而value的值可以是字符串,也可以是文档.所以我们在使用的过程中非常方 ...

随机推荐

  1. T430 Windows 8 的USB3.0无法识别

    去年10月入的T430,开始操作系统用的Win7,USB3.0的移动硬盘可以识别.后来,等到T430的Win8驱动都出来一段时间后,安装了Win8.开始没发现USB3.0不能使用,后来用移动硬盘是才发 ...

  2. NetFlow

    供应商 支持的流 设备列表 Cisco NetFlow Cisco - 800.1700.2600.1800.2800.3800.4500.6500.7200.7300.7500.7600.10000 ...

  3. Lastpass&mdash;&mdash;密码管理工具

    Lastpass是一个优秀的在线密码管理器和页面过滤器,采用了强大的加密算法,自动登录/云同步/跨平台/支持多款浏览器. 我之前一直都在使用这个工具,不过都是在浏览器上以扩展的方式使用,在火狐浏览器上 ...

  4. 全卷积网络 FCN 详解

    背景 CNN能够对图片进行分类,可是怎么样才能识别图片中特定部分的物体,在2015年之前还是一个世界难题.神经网络大神Jonathan Long发表了<Fully Convolutional N ...

  5. oracle12C安装步骤

    首先去官网下载两个架包链接如下:官网链接 第一步:将两个架包解压到同一个database目录下.如截图所示: 第二步:打开setup应用程序 打开后就到了下面这个页面 第三步:配置安全更新 环境变量配 ...

  6. Web-Business-Application-Solution

    项目地址 :  https://github.com/kelin-xycs/Web-Business-Application-Solution Web-Business-Application-Sol ...

  7. 9款原型设计工具与Sketch的强强组合,轻松构建交互原型!

    原型设计的发展历史经历了纸上原型.静态线框设计.到现在的可交互式原型.作为设计过程中最初始的阶段,设计师们对原型设计的要求也越来越高.因此,如今的原型设计工具格局也发生了很大的变化. Sketch对于 ...

  8. 使用Charles对Android App的https请求进行抓包

    本文背景 公司新项目要求抓取目前市面上一些热门App的数据,经过研究发现很多App的网络请求都使用https进行数据传输,这样问题就来了,http使用明文传输所有请求都能拦截到,而https请求无法拦 ...

  9. RSA加密工具类(非对称加密算法)

    import com.jfinal.log.Log;import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; ...

  10. XML删除节点

    XmlDocument doc = new XmlDocument(); doc.Load("Order.xml"); XmlNode xn = doc.SelectSingleN ...