MongoDB的学习--索引
索引可以用来优化查询,而且在某些特定类型的查询中,索引是必不可少的。为集合选择合适的索引是提高性能的关键。
先来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的学习--索引的更多相关文章
- MongoDB的学习--索引类型和属性(转)
原文链接:MongoDB的学习--索引类型和属性 索引类型 MongDB的索引分为以下几种类型:单键索引.复合索引.多键索引.地理空间索引.全文本索引和哈希索引 单键索引(Single Field I ...
- MongoDB的学习--索引类型和属性
索引类型 MongDB的索引分为以下几种类型:单键索引.复合索引.多键索引.地理空间索引.全文本索引和哈希索引 单键索引(Single Field Indexes) 在一个键上创建的索引就是单键索引, ...
- [转载]MongoDB开发学习(2)索引的基本操作
索引能够极大的提高查询的效率.在数据库中简历索引必不可少. 在MongoDB中可以很轻松的创建索引. 默认索引_id_ 开启MongoDB服务器,创建数据库cnblogs,创建集合Users .(关于 ...
- MongoDB数据模型和索引学习总结
MongoDB数据模型和索引学习总结 1. MongoDB数据模型: MongoDB数据存储结构: MongoDB针对文档(大文件採用GridFS协议)採用BSON(binary json,採用二进制 ...
- NoSQL之【MongoDB】学习(三):配置文件说明
摘要: 继上一篇NoSQL之[MongoDB]学习(一):安装说明 之后,知道了如何安装和启动MongoDB,现在对启动时指定的配置文件(mongodb.conf)进行说明,详情请见官方. 启动Mon ...
- 深入理解MongoDB的复合索引
更新时间:2018年03月26日 10:17:37 作者:Fundebug 我要评论 对于MongoDB的多键查询,创建复合索引可以有效提高性能.这篇文章主要给大家介绍了关于MongoDB复 ...
- MongoDB的学习--explain()和hint()
Explain 从之前的文章中,我们可以知道explain()能够提供大量与查询相关的信息.对于速度比较慢的查询来说,这是最重要的诊断工具之一.通过查看一个查询的explain()输出信息,可以知道查 ...
- mongodb的地理位置索引
mongoDB支持二维空间索引,使用空间索引,mongoDB支持一种特殊查询,如某地图网站上可以查找离你最近的咖啡厅,银行等信息.这个使用mongoDB的空间索引结合特殊的查询方法很容易实现.前提条件 ...
- 双刃剑MongoDB的学习和避坑
双刃剑MongoDB的学习和避坑 MongoDB 是一把双刃剑,它对数据结构的要求并不高.数据通过key-value的形式存储,而value的值可以是字符串,也可以是文档.所以我们在使用的过程中非常方 ...
随机推荐
- 快速排序-java
排序-快速排序 基本思想: 将数据划分为两部分,左边的所有元素都小于右边的所有元素:然后,对左右两边进行快速排序. 划分方法: 选定一个参考点(中间元素),所有元素与之相比较,小的放左边,大的放右边. ...
- Bookstore project using XAMPP 详细配置 Part 1
这是学校的一个project,记录在这里,以备复习.主要是用XAMPP通过phpMyAdmin连接MySQL数据库,实现一个简单的查询功能. Outline Setup of XAMPP Implem ...
- iOS CGContextRef画图时的常用方法
UIView的drawRect方法 CoreGraphics绘图 综述:描述系统会调用UIView的drawRect方法,所以coreGraphics的所有实现代码放在该函数内,setNeedsDis ...
- android adb install
环境:centos6.8 需要安装 root@localhost ~]# yum install libstdc++.so.6 1.下载安装包; http://pan.baidu.com/s/1skg ...
- MySql与Oracle的区别总结
在平时工作中使用这两个数据库的时候要多一些,这两数据库的使用方面存在的一些各自不同的地方,许多面试官也会问这两个的区别.所以,凭着自己的一些经验个感触,来说说这二者的区别. 使用的群众:MySql中小 ...
- 使用gson在解析unicode时遇到的问题
之前在用gson解析的时候未记录下来,所以今天做一个小的总结, 比如遇到像这种"\u003d"的unicode的字符,我们想解码这个字符,用gson可以这样表达 Gson gson ...
- MVC4 学习备忘
WebConfig文件里添加数据库链接字符: <add name="MovieDBContext(可以自己取字符串名字)" connectionString="Da ...
- 搭建coreseek(sphinx+mmseg3)详细安装配置+php之sphinx扩展安装+php调用示例
http://blog.csdn.net/e421083458/article/details/21529969 常用的命令 ps -ef|grep searchd 如果你开了search服务后,你命 ...
- Swift 对比学习 (二)
书接上回,可以作为参数和返回值的函数数型,以及嵌套函数,绝对继承了动态语言的优良传统: 函数嵌套了,那必然少不了闭包问题,Swift的闭包表达式语法也蛮有趣的. { (paraeeters) -> ...
- SQL入门经典(六) 之视图
视图实际上就是一个存储查询,重点是可以混合和匹配来自基本表(或其他视图)的数据,从而创建在很多方面象另一个普通表那样的起的作用.可以创建一个简单的查询,仅仅从一个表(另一个视图)选择几列或几行,而忽略 ...