玩转mongodb(六):索引,速度的引领(普通索引篇)
数据库索引与书籍的索引类似,有了索引就不需要翻整本书,数据库可以直接在索引中查找,在索引中找到条目后,就可以直接跳到目标文档的位置,这可以让查找的速度提高几个数量级。
一、创建索引
我们在person这个集合的age键上创建一个索引,比较一下创建索引前后,一个查询的语句的性能区别。
创建索引:db.person.ensureIndex({"age":1})。这里我们使用了ensureIndex在age上建立了索引。“1”:表示按照age进行升序,“-1”:表示按照age进行降序。
没有索引的查询性能:
有索引的查询性能:
我们主要来看这几个参数,(参数说明,请看上一篇文章)
executionTimeMillis(这次query整体的耗时):无索引耗时毫秒 ;有索引耗时毫秒。
totalDocsExamined(文档扫描条目):无索引是200万条;有索引是条。
stage(查询的类型):无索引是COLLSCAN(全表扫描);有索引是FETCH+IXSCAN(索引扫描+根据索引去检索指定document)。
executionStages.executionTimeMillisEstimate(检索document获得数据的耗时):无索引耗时毫秒;有索引耗时毫秒。
建好索引后,这个query整体的速度提高了1个数量级 (1个数量级是10倍的意思)。根据查询语句的不同,索引可以使速度提高几个数量级。
二、复合索引
在多个键上建立的索引就是复合索引,有时候我们的查询不是单条件的,可能是多条件,比如查找年龄在20~30名字叫‘ryan1’的同学,那么我们可以建立“age”和“name”的联合索引来加速查询。
为了演示索引的效果,我们来重新生成插入一份200万个文档的集合。
//删除原来的集合
db.person.drop(); //插入200万条数据
for(var i=0;i<2000000;i++){
db.person.insert({"name":"ryan"+i%1000,"age":20+i%10});
} //创建三个索引
db.person.ensureIndex({"age":1})
db.person.ensureIndex({"name":1,"age":1})
db.person.ensureIndex({"age":1,"name":1})
我们可以用hint()方法来强制查询走哪个索引。
我们来看一下,当查询条件是多个的时候,复合索引相比单键索引的强大魅力。
db.person.find({"age":{"$gte":20,"$lte":30},"name":"ryan1"}).hint({"age":1}).explain("executionStats");
{
...
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 2000,
"executionTimeMillis" : 2031,
"totalKeysExamined" : 2000000,
"totalDocsExamined" : 2000000,
...
}
db.person.find({"age":{"$gte":20,"$lte":30},"name":"ryan1"}).hint({"age":1,"name":1}).explain("executionStats");
{
...
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 2000,
"executionTimeMillis" : 8,
"totalKeysExamined" : 2010,
"totalDocsExamined" : 2000,
...
}
从executionTimeMillis的值上,一眼就可以看出却别。单间索引耗费了2031毫秒,复合索引用了8毫秒。 由此我们可以看出,根据查询语句的不同,建立正确的索引是非常重要的,对于查询语句中是多条件的,应多考虑复合索引的应用。
下面,我们再说一种复合索引的重要应用情况。有对一个键排序并只要前100个结果的情景(实际项目中经常都是这种情景)。对于这种情况,索引应该这样建{"sortKey":1,"queryCriteria":1},排序的键应该放在复合索引的第一位。
db.person.find({"age":{"$gte":21.0,"$lte":30.0}}).sort({"name":1}).limit(100).hint({"age":1,"name":1}).explain("executionStats");
{
...
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 100,
"executionTimeMillis" : 6882,
"totalKeysExamined" : 1800000,
"totalDocsExamined" : 1800000,
...
}
db.person.find({"age":{"$gte":21.0,"$lte":30.0}}).sort({"name":1}).limit(100).hint({"name":1,"age":1}).explain("executionStats");
{
...
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 100,
"executionTimeMillis" : 3,
"totalKeysExamined" : 2100,
"totalDocsExamined" : 2100,
...
}
从上面的结果,我们很容易看出,基于排序键的索引,效果非常好。
分析:第一种索引,需要找到所有复合查询条件的值(依据索引,键和文档可以快速找到),但是找到后,需要对文档在内存中进行排序,这个步骤消耗了非常多的时间。第二种索引,效果非常好,因为不需要在内存中对大量数据进行排序。但是,MongoDB不得不扫描整个索引以便找到所有文档。因此,如果对查询结果的范围做了限制,那么MongoDB在几次匹配之后就可以不再扫描索引,在这种情况下,将排序键放在第一位是一个非常好的策略。
三、唯一索引
唯一索引可以确保集合的每个文档的指定键都有唯一值。如果想保证不同文档的“name”键拥有不同的值,在“name”键上创建一个唯一索引就可以了。
db.person.ensureIndex({"name":1},{"unique":true});
然后用db.person.getIndexes()命令,查看目前person集合所有的索引。
也可以创建复合的唯一索引。创建复合唯一索引时,单个键的值可以相同,但所有键的组合值必须是唯一的。
db.person.ensureIndex({"name":1,"age":1},{"unique":true});
四、稀疏索引
唯一索引会把null看作值,所以无法将多个缺少唯一索引中的键的文档插入到集合中。然而,在有些情况下,你可能希望唯一索引只对包含相应键的文档生效。这个时候我们可以用到MongoDB中的稀疏索引。该索引与关系型数据库中的稀疏索引是完全不同的概念。MongoDB中的稀疏索引只是不需要将每个文档都作为索引条目。
比如,如果有一个可选的mobilephone字段,但是,如果提供了这个字段,那么它的值必须是唯一的:
db.person.ensureIndex({"mobilephone":1}{"unique":true,"sparse":true});
稀疏索引不必是唯一的。只要去掉unique选项,就可以创建一个非唯一的稀疏索引。
五、索引管理
如第一小节所述,可以使用ensureIndex方法创建新的索引,也可以使用createIndex方法。
创建一个索引之后,可以利用getIndexes()方法来查看给定集合上的所有索引的信息。
db.person.getIndexes();得到的结果如下所示。
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "personmap.person"
},
{
"v" : 1,
"unique" : true,
"key" : {
"name" : 1.0
},
"name" : "name_1",
"ns" : "personmap.person"
},
{
"v" : 1,
"unique" : true,
"key" : {
"name" : 1.0,
"age" : 1.0
},
"name" : "name_1_age_1",
"ns" : "personmap.person"
},
{
"v" : 1,
"unique" : true,
"key" : {
"mobilephone" : 1.0
},
"name" : "mobilephone_1",
"ns" : "personmap.person",
"sparse" : true
}
]
db.person.getIndexes()方法的结果
随着业务的不断变化,你可能会发现数据或者查询已经发生了改变,原来的索引也不那么好用了。这时可以使用dropIndex()方法删除不需要的索引:
db.person.dropIndex("name_1");//删除索引名为name_1的索引。
喜欢请微信扫描下面二维码,关注我公众号--“精修Java”,做一些实战项目中的问题和解决方案分享。
玩转mongodb(六):索引,速度的引领(普通索引篇)的更多相关文章
- 玩转mongodb(七):索引,速度的引领(全文索引、地理空间索引)
本篇博文主要介绍MongoDB中一些常用的特殊索引类型,主要包括: 用于简单字符串搜索的全文本索引: 用于球体空间(2dsphere)和二维平面(2d)的地理空间索引. 一.全文索引 MongoDB有 ...
- 玩转mongodb(九):通过log4jmongo来实现分布式系统的日志统一管理
背景 在分布式系统中,我们有多个web app,这些web app可能分别部署在不同的物理服务器上,并且有各自的日志输出.当生产问题来临时,很多时候都需要去各个日志文件中查找可能的异常,相当耗费人力. ...
- 玩转mongodb(五):mongodb 3.0+ 查询性能分析
mongodb性能分析方法:explain() 为了演示的效果,我们先来创建一个有200万个文档的记录.(我自己的电脑耗了15分钟左右插入完成.如果你想插更多的文档也没问题,只要有耐心等就可以了.) ...
- MongoDB学习笔记,基础+增删改查+索引+聚合...
一 基础了解 对应关系 -> https://docs.mongodb.com/manual/reference/sql-comparison/ database -> database ...
- 【Microsoft Azure 的1024种玩法】六、使用Azure Cloud Shell对Linux VirtualMachines 进行生命周期管理
[文章简介] Azure Cloud Shell 是一个用于管理 Azure 资源的.可通过浏览器访问的交互式经验证 shell. 它使用户能够灵活选择最适合自己工作方式的 shell 体验,本篇文章 ...
- MongoDB之几种情况下的索引选择策略
一.MongoDB如何选择索引 如果我们在Collection建了5个index,那么当我们查询的时候,MongoDB会根据查询语句的筛选条件.sort排序等来定位可以使用的index作为候选索引:然 ...
- MongoDB的备份和部署 高级功能索引,聚合复制,分片
创建备份 MongoDB 数据转储 为了在 MongoDB 中创建数据库备份,需要使用 mongodump 命令.该命令会将服务器上的所有数据都转储到 dump 目录中.你可以使用很多选项来限制转储的 ...
- IDEA 出现 updating indices 卡进度条问题的解决方案并加快索引速度
缺点: 这样的话,前端的接口(也就是字符串)就搜索不到了. C:\Users\Administrator\.IntelliJIdea2017.3\system 删除里面的caches文件夹(这里的 ...
- MongoDB快速入门(十二) -- 索引
MongoDB 索引 索引支持的解析度的查询效率.如果没有索引,MongoDB必须扫描每一个文档的集合,要选择那些文档相匹配的查询语句.这种扫描的效率非常低,会要求 mongod 做大数据量的处理. ...
随机推荐
- hdu 3664 Permutation Counting(水DP)
Permutation Counting Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- Java中HTTP通信
Java自带的get.post请求: get请求方式: package com.java; import java.io.BufferedReader; import java.io.IOExcept ...
- Android RelativeLayout属性介绍
在Android开发当中,虽然有五大布局,但我推荐使用的是相对布局,Google也是推荐使用相对布局,所有对RelativeLayout布局,常用的属性做一个整理: android:layout_ma ...
- Android 体系架构
什么是Android? 答:Android就是移动设备的软件栈,包括(一个完整的操作系统,中间件,关键应用程序), 底层是Linux内核,包括(安全管理, 内存管理,进程管理 ,电源管理,硬件驱动-) ...
- vs web项目远程发布到IIS
一.下载安装 IIS安装管理服务,这里不赘述,安装完后显示如下(装完刷新一下或者重新打开iis) 下载webploy,安装的时候要选中远程功能,或者选择完全安装,否则会因为没有远程模块导致连接失败(注 ...
- abp + angular $http + webapi 服务
什么是angular $http服务 http是angularjs的一个核心服务,用于读取远程服务器的数据,也就是封装了浏览器原生的xhtmlrequest对象,可以直接同外部进行通信. 怎样使用an ...
- SQL Server 紧急状态下的数据库恢复
背景:由于服务器硬盘损坏,服务器异常关机.重新进入后,数据库为质疑状态.(数据库名字上面有个感叹号,连接不了) 经过无数次的百度以及大佬们的指点下,终于成功恢复,下面来说一下方法. 第一种: 1.在服 ...
- application/force-download 不生效
不管用什么方式都无法下载txt 设置application/force-download也不生效 很无奈 胡搞瞎搞 最终解决方案:但是没搞明白什么原理 问题解决 @RequestMapping(val ...
- Day 19 re 模块 random模块,正则表达式
https://www.cnblogs.com/Eva-J/p/7228075.html#_label10 findall search match方法 和 search相比 match自带 ^ se ...
- Android------------fragment数据传递
一.activity向fragment的数值之间的传递 关键点:fragment.setArguments(bundle);---->activity发出的信息 Bundle bund ...