MongoDB系列四(索引).
一、索引简介
再来老生常谈一番,什么是索引呢?数据库索引与书籍的索引类似。有了索引就不需要翻整本书,数据库可以直接在索引中查找,在索引中找到条目以后,就可以直接跳转到目标文档的位置,这能使查找速度提高几个数量级。
然而,使用索引是有代价的:对于添加的每一个索引,每次写操作(插入、更新、删除)都将耗费更多的时间。这是因为,当数据发生变动时,MongoDB不仅要更新文档,还要更新集合上的所有索引。因此,MongoDB限制每个集合上最多只能有64个索引。通常,在一个特定的集合上,不应该拥有两个以上的索引。于是,挑选合适的字段建立索引非常重要。
- 索引基数
基数(cardinality)就是集合中某个字段拥有不同值的数量。比如 gender 字段,基数一般就男女 2个而已;而像 mobile 这样的字段,基数就会特别大。
通常来讲,一个字段的基数越高,这个字段上的索引就越有用。这是因为索引能够迅速将搜索范围缩小到一个比较小的结果集。对于低基数的字段,索引通常无法排除掉大量可能的匹配。假设我们在"gender"上有一个索引,需要查找名为Susan的女性用户。通过这个索引,只能将搜索空间缩小到大约50%。
tips:在关系型数据库中类似 gender 这样的字段可以使用位图索引。
- 索引原理浅析
我们以一个索引 {"age" : 1, "username" : 1} 来看看索引在MongoDB 中是如何存储的,大致是这个样子:

每一个索引条目都包含一个"age"字段 和 "username"字段,并且指向文档在磁盘中的存储位置。注意,这里的 age 严格的按照升序排序,并且相同的 age 对应的 username 也严格的按照升序排序。
来看个例子 :db.users.find({"age" : 21}).sort({"username" : -1})
这个索引对于这个查询来说是非常高效的,因为它可以马上定位到 age = 21 的位置,并且age = 21 中的 username 已经是排序好的。
tips:排序方向并不重要:MongoDB可以在任意方向上对索引进行遍历。
tips:查询中的字段顺序无关紧要,MongoDB 会自动找出可以使用索引的字段,而无视查询的字段顺序。
- $操作符如何使用索引
有一些查询完全无法使用索引,也有一些查询能够比其他查询更高效地使用索引。
$where:无法使用索引。
$nin:无法使用索引。
$exists:无法使用索引。因为在索引中,不存在的字段和null字段的存储方式是一样的,查询必须遍历每一个文档检查这个值是否真的为null还是根本不存在。
$ne:可以使用索引,但并不是很高效。因为必须遍历整个索引条目才能找到结果的文档。
$not:能够使用索引,但通常不知道如何使用索引,从而退化成全表扫描。
$or:能够使用索引,但是$or 查询会将 or 的条件拆分成多个独立的查询,然后再将结果合并在一起。这是很低效的,不建议用。建议用 $in 取代 $or 。
设计多键索引的时候要记得,要把基数大的字段放在索引的前面,因为这样能更快缩小查询的范围。
二、索引类型
- 复合(组合)索引
复合索引就是一个建立在多个字段上的索引。
如果查询中有多个排序方向或者查询条件中有多个键,复合索引就非常有效。
db.userInfo.ensureIndex({"age":1,"age":1})
进行多键排序时,索引的方向尤为重要。尽量做到多键排序的方向和复合索引的方向是一致的,因为这能很大的避免在内存中进行排序的运算。
tips:相互反转(在每个方向上都乘以-1)的索引是等价的:{"age" : 1, "user name" : -1}适用的查询与{"age" : -1, "username" : 1}是完全一样的。
复合索引具有双重功能,而且对不同的查询可以表现为不同的索引。如果有一个{"age" :1, "username" : 1}索引,"age"字段会被自动排序,就好像有一个{"age" : 1}索引一样。因此,这个复合索引可以当作{"age" : 1}索引一样使用。
- 唯一索引
唯一索引可以确保集合的每一个文档的指定键都有唯一值。我们熟悉的 "_id" 索引就是一个唯一索引(但它不能被删除,而其他唯一索引是可以删除的)。
db.users.ensureIndex({"username" : 1}, {"unique" : true})
定义了唯一索引后,这个键就不允许插入重复的值了,否则会抛异常。
tips:A 字段不存在 和 A 字段为 null 是互斥的!
在已有的集合上创建唯一索引可能会报错,因为集合中可能已经有重复的值了。在极少数情况下,可能希望直接删除重复的值。创建索引时使用"dropDups"选项,如果遇到重复的值,第一个会被保留,之后的重复文档都会被删除。
db.users.ensureIndex({"username" : 1}, {"unique" : true, "dropDups" : true})
- 稀疏索引
在有些情况下,你可能希望唯一索引只对包含相应键的文档生效。如果有一个可能存在也可能不存在的字段,但是当它存在时,它必须是唯一的,这时就可以将unique和sparse选项组合在一起使用,创建唯一稀疏索引。注意:MongoDB中的稀疏索引(sparse index)与关系型数据库中的稀疏索引是完全不同的概念。基本上来说,MongoDB中的稀疏索引只是不需要将每个文档都作为索引条目。并且,稀疏索引并不一定是唯一的。
db.ensureIndex({"email" : 1}, {"unique" : true, "sparse" : true})
当某个查询使用了稀疏索引,就不会返回不包含这个字段的文档。因为稀疏索引并没有把每个文档都作为索引条目。
- 覆盖索引
如果你的查询只需要查找索引中包含的字段,那就根本没必要获取实际的文档。当一个索引包含用户请求的所有字段,可以认为这个索引覆盖了本次查询。所以,尽可能使用投射筛选返回的字段,比如 {"_id":0,"age":1} 等,来实现覆盖索引。
三、索引管理
- 新建索引
普通索引
db.userInfo.ensureIndex({"name":1},{"name","MyIndex"})
"1" 表示按照name进行升序,"-1" 表示按照name进行降序。
默认的索引以 key1_1_key2_-1 这样的方式命名,可以手动指定索引的名字,如上。
对象索引

可以对整个对象建立索引,或者对对象的某个元素使用索引。
db.users.ensureIndex({"loc" : 1})
只有在进行与对象字段顺序完全匹配的子文档查询时(比如db.users.find({"loc" :{"ip" : "123.456.789.000", "city" : "Shelbyville", "state" :"NY"}}})),查询优化器才会使用"loc"上的索引。
db.users.ensureIndex({"loc.city" : 1})
有涉及到对象city的查询都会使用这个索引。
数组索引
对数组建立索引,实际上是对数组的每个元素建立一个索引条目。比如一个文档中的数组字段有20个元素,那么该文档就拥有了20个索引条目!所以对数组字段的索引建立要慎重。
- 删除索引
db.userInfo.dropIndexes("name_1")
删除指定索引
db.userInfo.dropIndexes()
删除除了_id 以外的所有索引
- 操作索引
获取当前索引列表:db.userInfo.getIndexes()
hint 暴力选择某种索引:db.userInfo.find({name:'zhangsan',birthday:'1989-3-2'}).hint({"name":1,"birthday":1})
强制使用全表扫描:db.userInfo.find({"birthday" : {"$lt" :"1989-3-2"}}).hint({"$natural" : 1})
索引分析函数explain:MongoDB 3.0前 和 MongoDB 3.0后存在很大的差异,这里只简单说明下,如果想详细了解的话,可以关注该作者的文章:
MongoDB 3.0 前:db.driverLocation.find({"areaCode":"350203"}).explain()
cursor:表扫描方式 (basicCursor:顺序查找)
nscanned:浏览了多少文档
n:最终返回了几个文档
millis:总共耗时了多少毫秒
scanAndOrder:是否必须在内存中对数据进行排序
MongoDB 3.0 后:db.driverLocation.find({"areaCode":"350203"}).explain("executionStats")
executionTimeMillis:该query的整体查询时间
nReturned:查询返回的条目
totalKeysExamined:索引扫描条目
totalDocsExamined:文档扫描条目
MongoDB系列四(索引).的更多相关文章
- MongoDB系列一(索引及C#如何操作MongoDB)
索引总概况 db.test.ensureIndex({"username":1})//创建索引 db.test.ensureIndex({"username": ...
- 4.MongoDB系列之索引(一)
1. 执行计划查看 db.getCollection('users').find({'username': 'shenjian'}).explain('executionStats') 结果查看,先大 ...
- MongoDB系列四:解决secondary的读操作
http://blog.itpub.net/26812308/viewspace-2124660/ 在Replica sets 中的secondary节点默认是不可读的.使用Replica Sets实 ...
- 5.MongoDB系列之索引(二)
1. $运算符如何使用索引 1.1 低效的运算符 $ne.$not查询可以使用索引,但不是很有效,尽量避免 1.2 范围查询 范围查询其实是多值查询,根据复核索引规则,尽可能先等值精确匹配,然后范围查 ...
- 【转载】8天学通MongoDB——第四天 索引操作
这些天项目改版,时间比较紧,博客也就没跟得上,还望大家见谅. 好,今天分享下mongodb中关于索引的基本操作,我们日常做开发都避免不了要对程序进行性能优化,而程序的操作无非就是CURD,通常我们 又 ...
- 8天学通MongoDB——第四天 索引操作
这些天项目改版,时间比较紧,博客也就没跟得上,还望大家见谅. 好,今天分享下mongodb中关于索引的基本操作,我们日常做开发都避免不了要对程序进行性能优化,而程序的操作无非就是CURD,通常我们 又 ...
- Node.js学习系列总索引
Node.js学习系列也积累了一些了,建个总索引方便相互交流学习,后面会持续更新^_^! 尽量写些和实战相关的,不讲太多大道理... Node.js学习笔记系列总索引 Nodejs学习笔记(一)--- ...
- MongoDB学习笔记(索引)
一.索引基础: MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧.下面是创建索引的命令: > db.test.ensureIndex({" ...
- MongoDB学习笔记(索引)(转)
一.索引基础: MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧.下面是创建索引的命令: > db.test.ensureIndex({" ...
随机推荐
- 深度揭秘腾讯云TSF日调用量超万亿次背后技术架构
腾讯云TSF是整合外部开源框架和腾讯内部历经多年锤炼的PaaS平台打造而成的企业级分布式应用服务开发与托管平台,本文重点对TSF中负责服务托管的PaaS平台进行揭秘,从技术角度解析TSF 平台是如何每 ...
- 为什么TCP的ISN是随机的?
两个维度: 1)攻击维度 如果TCP每次连接都使用固定ISN,黑客可以很方便模拟任何IP与server建立连接. 问题:通过抓包就可以计算出来TCP连接的ISN,那固定于不固定ISN有什么区别呢? 答 ...
- poj-1207 THE 3n+1 problem
Description Problems in Computer Science are often classified as belonging to a certain class of pro ...
- 选择排序—堆排序(Heap Sort) 没看明白,不解释
堆排序是一种树形选择排序,是对直接选择排序的有效改进. 基本思想: 堆的定义如下:具有n个元素的序列(k1,k2,...,kn),当且仅当满足 时称之为堆.由堆的定义可以看出,堆顶元素(即第一个元素) ...
- Django——ORM
Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...
- 【jQuery】 JQ和HTML以及JQ遍历元素
JQ & HTML JQ作为一个JS库,很好地继承了JS和HTML互动的特点,并且还给出了包装得更好,操作层次更高的方法.和之前JQ的内容一样,方法的表现形式是$(selector).acti ...
- 刚入大学B. http://mp.weixin.qq.com/s/ORpKfX8HOQEJOYfwvIhRew
自己对计算机还是比较感兴趣的,经过不断的努力,我相信我可以在这一专业中显露头角,我会努力向博主学习.理想的大学是自由,快乐,可以学到很多知识的地方,未来我想在lt行业进行软件开发等项目,为了梦想我会不 ...
- Beta No.2
今天遇到的困难: 组员对github极度的不适应 Android Studio版本不一致项目难以打开运行 移植云端的时候,愚蠢的把所有项目开发环境全部搬上去.本身云的内存小,性能差,我们花费了太多时间 ...
- C语言程序设计第四次作业——选择结构(2)
Deadline: 2017-11-5 22:00 一.学习要点 掌握switch语句 掌握字符常量.字符串常量和字符变量 掌握字符型数据的输入输出 二.实验内容 完成PTA中选择结构(2)的所有题目 ...
- 使用genstring和NSLocalizedString实现App文本的本地化
OS提供了简便的方法来实现本地化,其中用的最多的就是NSLocalizedString. 首先查看下NSLocalizedString是什么: #define NSLocalizedString(ke ...