Index 能够提高查询的性能,如果没有Index,MongoDB必须扫描整个collection,从collection的第一个doc开始,直到最后一个doc,即使第一个doc之后的所有doc都不满足查询条件。如果在Collection上有合适的Index,例如,unique index,那么MongoDB在按照index key查找到一个doc之后,就不会继续对其他doc查询,极大地提高查询性能。

MongoDB的 Index 结构跟关系型DB的NonClustered Index相似,都是BTree结构,在每个leaf node中,除了index key之外,还存储相应doc在disk上的地址。在MongoDB中,没有clustered index,因此,Collection初始的物理存储跟doc插入的顺序有关,MongoDB按照doc插入的顺序,依次将doc存储在disk上,插入顺序上相邻的doc在disk的物理位置上也是相邻的;对doc的修改可能对 collection 的物理存储发生变化,如果doc的修改不会导致doc的size增加,那么doc会继续存储在原来的存储空间中,而不会对collection的物理存储有影响,一旦修改操作导致doc的size增加,导致doc发生移动,那么collection的物理存储就会发生变化。

一,doc的移动影响collection的物理存储

如果数据修改增加了doc的size,使其不能继续存放在原来的存储空间中,那么MongoDB必须将其移动到collection的末尾,原先的存储空间被闲置,导致doc的存储密度下降,会严重影响查询性能。doc的移动过程是非常慢的,相当于在一个原子操作中,先做doc的 delete 操作,后做doc的 insert 操作。

doc移动的过程如下图所示:

对doc B进行修改,使其Size增大,原先的位置不能容纳B,MongoDB将B移动在Collection的末尾。原来的存储空间被闲置。

二,创建index

MongoDB的index是BTree 结构,BTee结构的特点是:查询每个值所要进行查询的次数时固定的,最小的值存储在最左边的叶子节点上,做大的值存储在最右边的叶子节点上,如图:

MongoDB默认按照“_id”字段的升序创建index,最后创建的doc位于index的右侧。如果每次查询时,都是查询最后的N个doc,那么按照"_id"的值倒叙查询,limit 前100,查询性能是十分快速的。也可以手动创建符合业务需要的Index,MongoDB使用 db.collection.createIndex(keys,option)函数创建index。

keys的格式是:{field:1/-1,,},field是doc的字段,1/-1 表示按照field排序的方向创建index:1表示按照field的升序创建,-1表示按照field的降序创建。

db.collection.createIndex(keys,option) 

1,创建示例数据,按照 age 字段升序创建index

创建的Index按照age的升序存储age字段,在叶子节点中,除了age字段,叶子节点还会存储doc的地址(指针),用于定位相应的doc,查询除index key(age)之外的其他字段。下面的语句创建的index name是 age_1。

for(i=0;i<10000;i++)
{
db.foo.insert({"idx":i,name:"user "+1,age:i%90})
} --create index by age ascendant
db.foo.createIndex({age:1})

2,查看查询的query plan

在示例中,由于查询语句中没有设置projection,MongoDB返回doc中的所有fields,由于index:age_1只包含age字段,其他字段必须定位到原doc中获取,因此多一次寻址操作。

db.foo.find({age:22}).explain("executionStats")

在查询语句中设置Projection,只返回age字段,那么index:age_1 就能包含结果集中所有字段,不需要定位到原doc中,不仅提高查询性能,而且减少Disk IO 和内存的使用量,因此,应对每个结果集设置Projection,不要返回"_id"字段等其他不需要的字段。通过搜索index就能获取所有field的index是覆盖索引(convered index),覆盖索引不需要定位到原doc中。

db.foo.find({age:22},{age:1,_id:0}).explain("executionStats")

三,index 和 排序

排序是一个非常耗费内存资源的操作,在MongoDB中,如果排序的中间结果集大小消耗的系统内存超过32MB,MongoDB就会报错,拒绝如此多的数据进行排序。32MB是一个阈值,如果超出值,那么必须使用 index 来获取经过排序的数据集。

MongoDB:When unable to obtain the sort order from an index, MongoDB will sort the results in memory, which requires that the result set being sorted is less than 32 megabytes. When the sort operation consumes more than 32 megabytes, MongoDB returns an error.

通过Index来执行排序操作,要求排序的字段和index key的前缀字段相同,如果满足该条件,那么MongoDB会直接返回顺序的结果集,而不需要执行实际的排序操作。例如,如果index key是{age:1,name:1},如果排序操作是sort({age:1}),或 sort({age:1,name:1}),符合index前缀排序,那么结果集会直接返回,不需要排序;如果排序操作是sort({name:1}),或sort({name:1,age:1}),不符合index前缀排序,结果集还是需要在内存中进行排序,如果内存消耗超过32MB,MongoDB报错。

示例,符合前缀排序的Index 和 sort 操作

 db.foo.find({age:22}).sort({age:1})

由于MongoDB通过Index来执行排序操作,并且MongoDB对排序操作消耗的内存资源有严格限制,因此,在创建index,应在查找和排序之间做折衷,在满足排序操作的前提下,使查询性能更高。在创建index时,使用 {"Sort Key":1, "query filter":1} 格式是非常有用。

四,对内嵌doc进行索引

MongoDB index的强大之处在于能够在内嵌doc的字段上创建index,创建的语法和普通doc一致,在引用内嵌doc中的字段时,使用dot notation,可以对任意深度的内嵌doc字段建立index。

例如,doc结构如下,contact是内嵌doc,按照 contact.phone 字段升序创建索引。

{
name:"u1",
age:22,
contact:
{
phone:123
email:"xx@163.com"
}
} --create index
db.foo.createIndex({"contact.phone":1})

五,Index 维护

1,查看在collection上创建的index

使用db.collectionName.getIndexes() 查看给定collection上的所有index信息:

  • key是指index key的定义,包括两部分:key 和排序的方向;
  • name是index name;
  • ns是namespace;
  • v 标识index 版本,如果索引中包含"v":1,说明index是以新格式存储的,性能较高。
db.collection.getIndexes()

2,删除index

db.collection.dropIndex(index)

方式一,按照index name 删除index

db.foo.dropIndex("age_1")

方式二,按照Index key删除index

db.foo.dropIndex({age:1})

3,重建collection中的所有index

db.collection.reIndex()

The db.collection.reIndex() drops all indexes on a collection and recreates them. This operation may be expensive for collections that have a large amount of data and/or a large number of indexes.

参考doc:

MongoDB CRUD Concepts

cursor.explain()

Indexes

MongoDB 使用Index的更多相关文章

  1. mongodb(Index)

    备忘mongoDb 索引的一些知识点. 1.索引是用以加速数据库查询的手段,在mongo中主要是采用B树的方式: 2.每个集合最多可增加64个索引,不建议增加过多索引,原因在于一是索引本身占用空间,二 ...

  2. mongodb query index 分析

    query 的过程及分析: query 是通过Query planner选择最有效的查询plan ,为一个query 被给予一个可用的索引,查询时 query optimizer(最优的查询条件选择器 ...

  3. MongoDB collection Index DB 大小查询

    1.collection中的数据大小 db.collection.dataSize() 2.为collection分配的空间大小,包括未使用的空间db.collection.storageSize() ...

  4. mongodb AND查询遇到多个index时候可能会做交集——和复合索引不同

    关于MongoDB中索引文档的一个问题? - To illustrate index intersection, consider a collection orders that has the f ...

  5. MongoDB之TextSearch简介

    MongoDB之TextSearch简介  MongoDB支持对文本内容执行文本搜索操作,其提供了索引text index和查询操作$text来完成文本搜索功能.下面我们通过一个简单的例子来体验一下M ...

  6. spring data mongodb中,如果对象中的属性不想加入到数据库字段中

    spring data mongodb中,如果对象中的属性不想加入到数据库字段中,可加@Transient注解,声明为透明属性 spring data mongodb 官网帮助文档 http://ww ...

  7. mongodb地理位置索引

    初始化集合(经度在前,纬度在后) ? 1 2 3 mongos> db.checkins.insert({ "_id" : "101", "lo ...

  8. Spring boot中使用Mongodb

    安装 使用Idea新建Spring boot工程时需要选择Mongodb 或者在工程中加入依赖 Maven: <dependency> <groupId>org.springf ...

  9. mongodb 数组查询

    转发自:https://blog.csdn.net/leshami/article/details/55049891 一.演示环境及数据> db.version() 3.2.11 > db ...

随机推荐

  1. 如何在Web引用中使用项目自定义的类

    这个是老架构了,不推荐现在这么用,维护一个老项目记录一下. 项目中WebService和客户端是在一个解决方案下,实体类是一个公用的Project,如果使用Web引用自动生成的类会缺少一些实体类定义的 ...

  2. Android开发 SQLite数据库应用笔记(一)

    注意: 1.public Cursor rawQuery(String sql, String[] selectionArgs) Cursor游标是查询后返回的结果集合,游标的意思是指向集合中的某行. ...

  3. 【填坑】bzoj3224 splay裸题

    人生第一道splay不出所料是一道裸题,一道水题,一道2k代码都不到的题 #include <cstdio> ,n,p,q; ],c[][],size[],sp[]; void rot(i ...

  4. C# 对多个文件进行zip压缩

    本文使用的ICSharpCode.SharpZipLib.dll类库来实现文件压缩,你可以通过Nuget来安装此类库,或者到搜索引擎去搜索一下遍地都是.类库下载下来之后,添加到项目引用就可以了.下面这 ...

  5. 关于The C compiler "arm-none-eabi-gcc" is not able to compile a simple test program. 的错误自省...

    在 GCC ARM Embedded https://launchpad.net/gcc-arm-embedded/ 上面下载了个arm-none-eabi-gcc 用cmake 编译时 #指定C交叉 ...

  6. 可变数组NSMutableArray

    //创建一个空的可变数组 NSMutableArray *array = [NSMutableArray array]; //向数组里面添加对象 [array addObject:@"< ...

  7. vs2012 打开解决方案崩溃或者点击项目崩溃

    报错: 问题签名:  问题事件名称: CLR20r3 解决方案: 步骤1:开始-->所有程序-->Microsoft Visual Studio 2012-->Visual Stud ...

  8. 单页web应用是什么?它又会给传统网站带来哪些好处?

    文章来源:<单页Web应用:JavaScript从前端到后端> 什么是单页应用? 单页应用是指在浏览器中运行的应用,它们在使用期间不会重新加载页面.像所有的应用一样,它旨在帮助用户完成任务 ...

  9. 05.DOM

    DOM基础 什么是DOM 标签元素节点浏览器支持情况  火狐支持最好 谷歌其次 ie最差 尤其是ie6-8DOM节点节点分为:元素节点和文本节点 测试节点的类型用nodeTypenodeType 为3 ...

  10. java并发编程(十九)障碍器CyclicBarrier

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17512983 CyclicBarrier(又叫障碍器)同样是Java 5中加入的新特性,使 ...