MongoDB索引原理和具体使用
1. MongoDB 索引是用来干嘛?
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
简单举例分析下:
假设这里有一个 commits 集合,我们想要查询其中的数据!
db.commits.find({"eId":"5913cd0ee727e70007a109f2"}).explain("executionStats")
从执行计划来看,我们从18284条数据中查询得到了80条查询结果集,而我们文档中的记录数就是18284条记录,说明这条查询语句是全表搜索,显然这是非常浪费效率的。
2. 创建单索引
为了提高查询效率,我们可以使用创建索引的方式,mongodb使用createIndex方法来创建索引语法:
db.collection_name.createIndex(keys[,options])
这时我们给commits集合的eId这个字段创建索引
db.commits.createIndex({eId:1})
索引创建成功之后,这时再查询commits集合
db.commits.find({"eId":"5913cd0ee727e70007a109f2"}).explain("executionStats")
我们查询得到的数据是80条,而我们一共只在80条数据里查询,从执行记划来看,查询的记录数,查询的时间明显都缩小。
从上图,如果我们想给sinfo下面的name加索引,可以这样写
db.commits.createIndex({"sinfo.name":1})
我们不在要sinfo上面加索引,如果这样做了,我们必须查询整个子方档。
createIndex()接收可选參数,可选參数列表例如以下:
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会堵塞其他数据库操作,background可指定以后台方式创建索引,即添加 “background” 可选參数。 “background” 默认值为false。 |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name | string | 索引的名称。假设未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
dropDups | Boolean | 在建立唯一索引时是否删除反复记录,指定 true 创建唯一索引。默认值为 false. |
sparse | Boolean | 对文档中不存在的字段数据不启用索引。这个參数须要特别注意。假设设置为true的话,在索引字段中不会查询出不包括相应字段的文档.。默认值为 false. |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完毕 TTL设定,设定集合的生存时间。 |
version | index version | 索引的版本号号。默认的索引版本号取决于mongod创建索引时执行的版本号。 |
比如说:创建唯一索引,方法就是指定unique键为true,如:
db.users.createIndex({name:1},{“unique”:true})
3. 复合索引
当我们的查询条件不只有一个时,就需要建立复合索引。复合索引是两个或更多字段的索引,并且它可以支持基于这些字段的查询。当我们查询时有多个过滤条件时,为了提高查询效率,可以在这多个条件上添加索引,语法
db.collection_name.createIndex(key1:1,key2:1)
当我们查询条件为两个时,如:
db.commits.find({"eId":"5913cd0ee727e70007a109f2","sId":"5913c700434a8b00077256fe"}).explain("executionStats")
因前面已经给eId创建了索引,所以本次查询范围从18248条记录,降到了80条记录,而sId没有创建索引,所有我们从80条记录里得到了符合eId,sId这两个条件的38条记录,那么我们现在给sId也创建索引
db.commits.createIndex({sId:1})
当查询的两个条件sId,eId都创建了索引后,再执行
db.commits.find({"eId":"5913cd0ee727e70007a109f2","sId":"5913c700434a8b00077256fe"}).explain("executionStats")
4. 多键索引
如果文档中含有array类型字段,可以直接对其名称建立索引,这样MongoDB就会为内嵌数组中的每个元素建立一个独立的索引
注意:多键索引不等于在多列字段上创建索引(复合索引),多键索引与单键索引创建形式相同,差别在于字段的类型.
语法:
db.COLLECTION_NAME.createIndex({key:< 1 or -1 >})
如:
有一个paper集合,数据表结构如下,其中structures字段是数组类型。
例如:这时我们给papers集合的structures这个字段创建索引
db.papers.createIndex({structures:1})
因为这个structures字段是数组,所有这个索引称之为多键索引。
5.复合多键索引
对于一个复合多键索引,每个索引最多可以包含一个数组。在多于一个数组的情形下来创建复合多键索引不被支持。
假定存在如下集合
{ _id: 1, a: [ 1, 2 ], b: [ 1, 2 ], category: "AB - both arrays" }
你可能会这样创建索引db.COLLECTION_NAME.createIndex({a:1,b:1}),但是这样是不允许的,因为a和b都是数组。
如果{a:1,b:1}的索引已经创建了,则a和b当中必定有一个是非array,此时插入一个a和b都是array的文档就会失败。
假定存在如下集合
{ _id: 1, a: [1, 2], b: 1, category: "A array" }
{ _id: 2, a: 1, b: [1, 2], category: "B array" }
则可以基于每一个文档创建一个基于{ a: 1, b: 1 }的复合多键索引,原因是每一个索引的索引字段只有一个数组
类似的,如下的内嵌文档也可以建立索引。例如:
db.test.createIndex({“stock.size”:1,”stock.quantity”:1})
6.部分索引
MongoDB部分索引只为那些在一个集合中,满足指定的筛选条件的文档创建索引。由于部分索引是一个集合文档的一个子集,因此部分索引具有较低的存储需求,并降低了索引创建和维护的性能成本。
部分索引通过指定过滤条件来创建,可以为MongoDB支持的所有索引类型使用部分索引。
简单点说:部分索引就是带有过滤条件的索引,即索引只存在与某些文档之上
创建部分索引语法:
db.collection.createIndex(keys, options)
options可以使用partialFilterExpression,即部分过滤表达式,其类型为文档类型
过滤表达式通常包括:$exists, $gt, $gte, $lt, $lte,$type,$and
过滤表达式使用示例:
db.persons.createIndex({name:1},{partialFilterExpression:{age: {$gt:25}}})
此句的意思是:基于age列创建大于25岁的部分索引。
创建的部分索引过滤条件是age大于25,
当查询的条件是country等于china,age大于25。 条件满足,从执行计划里可以看出此次查询采用索引扫描。
当查询的条件是country等于china,age大于等于25。 条件不满足,从执行计划里可以看出此次查询采用的是全表扫描方式。
创建部分唯一索引的一些限制:
部分索引只为集合中那些满足指定的筛选条件的文档创建索引。 如果你指定的partialfilterexpression和唯一约束、那么唯一性约束只适用于满足筛选条件的文档。 具有唯一约束的部分索引不会阻止不符合唯一约束且不符合过滤条件的文档的插入。
示例文档
db.users.insertMany([
{ "_id" : ObjectId("56424f1efa0358a27fa1f99a"), "username" : "david", "age" : 29 },
{ "_id" : ObjectId("56424f37fa0358a27fa1f99b"), "username" : "amanda", "age" : 35 },
{ "_id" : ObjectId("56424fe2fa0358a27fa1f99c"), "username" : "rajiv", "age" : 57 }])
为集合添加索引
db.users.createIndex({ username: 1 },
{ partialFilterExpression: { age: { $gte: 21 } } })
在集合users上插入用户名相同的文档,收到了重复键的错误提示
db.users.insert( { username: "david", age: 27 } )
WriteResult({"nInserted" : 0,"writeError" : {"code" : 11000,"errmsg" : "E11000 duplicate key error collection: test.users index: username_1 dup key: { : \"david\" }"}
})
下面插入年龄小于部分索引值或者age键为空的同用户名文档,可以成功插入。
也就是说对于不在部分索引限制之类的其他键值重复是允许的。
db.users.insert( { username: "david", age: 20 } )
WriteResult({ "nInserted" : 1 })db.users.insert( { username: "amanda" } )
WriteResult({ "nInserted" : 1 })db.users.insert( { username: "rajiv", age: null } )
WriteResult({ "nInserted" : 1 })
7.文本索引
MongoDB提供文本索引以支持对字符串内容的文本搜索查询。text索引可以包括其值为字符串或字符串元素数组的任何字段。
文本索引,顾名思义就是用于搜索文本的,可以用于搜索所有的value,也可以搜索指定的field对应的value。只要field对应value是string,或者对应的value是array且array中的元素是string,那么文本索引都可以索引该field
注意:一个集合最多只能有一个文本索引。
要创建text索引,请使用该 db.collection.createIndex()方法。要索引包含字符串或字符串元素数组的字段,请包含该字段并"text"在索引文档中指定字符串文字。
如以下示例所示:
db.collection.createIndex({keys:”text”})
也可以创建多个字段text,例如
db.collection.createIndex({subject:”text”,comments:”text”})
举例,有两条记录
{_id:5908df789dfd1fd5884fd84f7df4,statement:MongoDB is the worst}{_id:5908dfgfh587hgf15f4hf54hf418,statement:MongoDB is the best}
给statement字段创建文本索引:
db.collection.createIndex({statement:”text”})
查询
db.collection.find({$text:{$search:”MongoDB best”}})
查询出来的结果集是:
{_id:5908df789dfd1fd5884fd84f7df4,statement:MongoDB is the worst}{_id:5908dfgfh587hgf15f4hf54hf418,statement:MongoDB is the best}
这是因为文本查询时,每个单词之间的分隔是”或者”,所以上面的查询语句的意思是:查询包含MongoDB或者best的记录数。
在多个字段上创建文本索引时,还可以使用通配符说明符($**)。使用通配符文本索引,MongoDB会为包含集合中每个文档的字符串数据的每个字段编制索引。
例如:
db.collection.createIndex({“$**”,”text”})
此索引允许在具有字符串内容的所有字段上进行文本搜索。如果不清楚要包含在文本索引中的哪些字段或用于临时查询
通配符文本索引可以是复合索引的一部分。例如,以下内容在字段nane和通配符说明符上创建复合索引,例如:
db.collection.createIndex({name:1,“$**”,”text”})
排序操作无法从text索引获取排序顺序,即使是复合文本索引也是如此 ; 即排序操作不能使用文本索引中的排序。
8.唯一索引
只要指定了某个field是唯一的,那么在同一个集合中就不允许存在相同的field值,MongoDB默认创建的唯一索引就是_id。
唯一索引一般是这样创建的:
db.members.createIndex( { "user_id": 1 }, { unique: true } )
单索引创建唯一索引,如:
db.persons.createIndex({name:1},{unique:true})
复合键创建唯一索引,如:
db.persons.createIndex({name:1,email:1},{unique:true})
9.查看索引:
MongoDB提供的查看索引信息的方法:
- getIndexes()方法可以用来查看集合的所有索引,
- getIndexKeys()方法查看索引键。
- totalIndexSize()查看集合索引的总大小,
- getIndexSpecs()方法查看集合各索引的详细信息db
MongoDB默认会为插入的文档生成_id字段(如果应用本身没有指定该字段),_id是文档唯一的标识,为了保证能根据文档id快递查询文档,MongoDB默认会为集合创建_id字段的索引。
例1: getIndexes()的用法
> db.exams.getIndexes()
[{"v" : 2, //索引版本"key" : { //索引的字段及排序方向 "_id" : 1 //根据_id字段升序索引},"name" : "_id_", //索引的名称"ns" : "Steam.exams" //集合名}
]
例2:getIndexKeys()的用法
> db.exams.getIndexKeys()
[ { "_id" : 1 } ]
例3:totalIndexSize()的用法
> db.exams.totalIndexSize()
65536
10.删除索引:
不再需要的索引,我们可以将其删除,mongodb提供两种删除索引的方法:
- dropIndex()方法用于删除指定的索引
- dropIndexes()方法用于删除全部的索引
例1:dropIndex()的用法
> db.users.dropIndex()
11.注意:
11.1 MongoDB中索引是大小写敏感的。
当更新对象是,只有在索引上的这些key发生变化时才会更新。着极大地提高了性能。当对象增长了或者必须移动时,所有的索引必须更新,这回很慢 。
索引信息会保存在system.indexes 集合中,运行 db.system.indexes.find() 能够看到这些示例数据。
索引的字段的大小有最大限制,目前接近800 bytes. 可在大于这个值的字段上建立索引是可以的,但是该字段不会被索引,这种限制在以后的版本中可能被移除。
11.2 索引的性能
索引使得可以通过关键字段获取数据,能够使得快速查询和更新数据。
但是,必须注意的是,索引也会在插入和删除的时候增加一些系统的负担。往集合中插入数据的时候,索引的字段必须加入到B-Tree中去。
因此,索引适合建立在读远多于写的数据集上,对于写入频繁的集合,在某些情况下,索引反而有副作用。不过大多数集合都是读频繁的集合,所以集合在大多数情况下是有用的。
11.3 使用sort()而不需要索引
如果数据集合比较小(通常小于4M),使用sort()而不需要建立索引就能够返回数据。在这种情况下,做好联合使用limit()和sort()。
MongoDB索引原理和具体使用相关推荐
- MongoDB · 引擎特性 · MongoDB索引原理
MongoDB · 引擎特性 · MongoDB索引原理 数据库内核月报 原文链接 http://mysql.taobao.org/monthly/2018/09/06/ 为什么需要索引? 当你抱怨M ...
- MongoDB索引原理及实践
背景 数据库的演进 随着计算机的发展,越来越多的数据需要被处理,数据库是为处理数据而产生.从概念上来说,数据库是指以一定的方式存储到一起,能为多个用户共享,具有更可能小的冗余,与应用程序彼此独立的数据 ...
- MongoDb 索引原理
(一)索引基本介绍 索引是提高查询查询效率最有效的手段.索引是一种特殊的数据结构,索引以易于遍历的形式存储了数据的部分内容(Mongodb和Mysql使用B+树)(如:一个特定的字段或一 ...
- 学习 | MongoDB 索引和排序
小小又开始学习了,这次学习的内容是索引和排序. 索引 先给users集合插入两条记录,然后用users集合来进行索引管理的演示: > user1={"name":" ...
- MongoDB索引优化
MongoDB 索引优化 1. 一图看懂索引原理 2. 查看执行计划 3. 如何建索引 3. 索引的优化 4. 索引的选择机制 5. 优化实践 country_themes 优化 wallpapers ...
- 【大数据存储技术】第7章 MongoDB 的原理和使用
文章目录 第7章 MongoDB 的原理和使用 7.1 概述 7.2 MongoDB 技术原理 7.2.1 文档和集合 7.2.2 分片机制和集群架构 7.2.3 CouchDB 简介 7.3 安装配 ...
- Mysql索引原理剖析与优化策略
Mysql索引原理剖析与优化策略 1.索引的本质 在⽣产环境中,随着数据量不断的增⻓,SQL执⾏速度会越来越慢,常⻅的⼿段就是通过索引来提升查询速度,那么究竟为什么要添加索引?应该如何正确添加索引? ...
- M14-MongoDB索引原理及使用
存储引擎 network-Query Pan-Storage KV Interface-WiredTiger 核心数据结构B-Tree MongoDB数据结构组织 索引原理总结 MongoDB索引类型 ...
- MongoDB分布式原理以及read-preference和readConcern解决读写一致性问题
MongoDB词汇表: https://docs.mongodb.com/manual/reference/glossary/#term-replica-set MongoDB分布式原理 primar ...
最新文章
- 迁移学习(Transfer learning)、重用预训练图层、预训练模型库
- Spring学习手册番外:context:annotation-config/ 和 mvc:annotation-driven / 的区别
- 开发日记-20190706 关键词 读书笔记 《Perl语言入门》Day 3
- 【AI不惑境】模型压缩中知识蒸馏技术原理及其发展现状和展望
- python日志文件保存在哪里,Python日志记录-检查日志文件的位置?
- php多线程swoole,swoole究竟能够多线程么_PHP开发框架教程
- 【数据结构与算法】之深入解析“比特位计数”的求解思路与算法示例
- Android性能优化典范(转)
- 讯飞输入法有没有Linux,Debian testing 安装讯飞输入法 - Linux系统与应用 - LinuxApp - 水木社区...
- 大型集团企业云管平台建设参考架构
- Oracle 查找带有CLOB字段的所有表
- 过去15年,到底是什么真正推动了云计算的革命?
- 烽烟通讯2100万限售股将于3月7日疏通流畅上市
- 综合能源系统通用建模及规划方法研究—笔记
- cs229 学习笔记四 学习理论
- 评委对计算机知识竞赛的提问,知识竞赛抢答软件-评委评分知识竞赛答题软件...
- youtube的使用体会
- 为什么保险公司一直不停地招人?
- 万字长文!浏览器是如何工作的:Chrome V8让你更懂JavaScript
- 爬虫基础篇之多途径抓取失信人名单
热门文章
- 单例设计模式-饿汉式
- FastDFS配置手册trackerstorage
- 表贴电阻尺寸与什么有关_电路板上为什么会有0欧电阻这种东西?
- c语言进程调度报告,进程调度(C语言实现).doc
- 简易 IM 双向通信电脑端 GUI 应用——基于 Netty、WebSocket、JavaFX 、多线程技术等
- Maven 配置文件 POM 的常用依赖配置代码
- 图像像素灰度内插(Matlab实现)
- 慕课-北京理工大学 机器学习 大学生上网时间 聚类,小白学习
- cordova项目适配iPhoneX
- centos 安装PHP7并且与其他版本共存并且为PHP7安装redis扩展