这章我们介绍MongoDB的索引,用来优化查询。

索引介绍

数据库索引有些类似书的目录。

一个查询如果没有使用索引被称为表扫描,意思是它必须像阅读整本书那样去获取一个查询结果。一般来说,我们应尽量避免这种情况,

因为它是非常慢的。

举个例子,我们创建一个百万条数据的collection:

for(i=0;i<1000000;i++){
db.users.insert({
"i":i,
"username":"user" + i,
"age":Math.floor(Math.random()*120),
"created":new Date()
  })
}

假如我们查找这个collection,我们可以使用explain()来查看详细的查询信息。例如:

db.users.find({username:"user101"}).explain();

返回

{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1000000,
"nscanned" : 1000000,
"nscannedObjectsAllPlans" : 1000000,
"nscannedAllPlans" : 1000000,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 7812,
"nChunkSkips" : 0,
"millis" : 521,
"server" : "Colin_xu:27017",
"filterSet" : false
}

上述信息要点:

"cursor":"BasicCursor"说明查询没有使用索引

"nscanned":1000000   代表查询了多少文档

"n":1   代表返回文档的数量

"millis":521 代表数据库执行查询的时间(毫秒)

这时我们加上索引:

db.user.ensureIndex({"username":1})

这时再查询的返回结果:

{
"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" : 47,
"indexBounds" : {
"username" : [
[
"user101",
"user101"
]
]
},
"server" : "Colin_xu:27017",
"filterSet" : false
}

这时我们看看两次结果的misllis,差距显而易见。

复合索引

当查询中排序中仅使用一个键时,可以对该键建立索引,以提高查询速度。然而,对于其他查询可能没有帮助,即便是查询包含了被索引的键。

所以,一定要创建查询中用到所有键的索引。

索引名称

集合中的每个索引都有一个字符串类型的名字,来唯一标识索引,服务器通过这个名字来删除或者操作索引。

默认情况下,索引名类似keyname1_dir1_keyname2_dir2_..._keynameN_dirN这种形式,其中keynameX代表索引的键,

dirX代表索引的方向(1或者-1)。要是索引的键特别多,这样命名就略显愚笨,不过还好可以通过ensureIndex的选项来自定义名字。

db.foo.ensureIndex({"a":1,"b":1,"c":1,...,"z":1},{"name":"alphabet"})

索引名有字符个数的限制,所以特别复杂的索引在创建时一定要用自定义名字。

唯一索引

唯一索引可以确保集合的每一个文档的指定键都有唯一值。例如,如果想保证文档的"username"键都有不一样的值,创建一个唯一索引就好了:

db.users.ensureIndex({"username":1},{"unique":true});

消除重复

当为已有的集合创建索引,可能有些值已经有重复了。若是真的发生这种情况,那么索引的创建就是失败。有些时候,可能希望将所有包含重复值的文档都删掉。

dropDups选项就可以保留发现的第一个文档,而删除接下来的有重复值的文档:

db.people.ensureIndex({"username":1},{"unique":true,"dropDups":true})

地理空间索引

还有一种查询变得越来越流行(尤其是随着移动设备的出现);找到离当前位置最近的N个场所。MongoDB为坐标平面查询提供了专门的索引,称为地理空间索引。

假设要找到给定经纬度周围最近的咖啡馆,就需要创建一个专门的索引来提高这种查询的效率,这是因为这种查询需要搜索两个维度。地理空间索引同样可以由ensureIndex来创建,

只不过参数不是1,而是"2d";

db.map.ensureIndex({"gps":"2d"})

"gps"键的值必须是某种形式的一对值:一个包含两个元素的数组或是包含两个键的内嵌文档。下面这些都是有效的:

{"gps":[0,100]};

{"gps":{"x":-30,"y":30}};

{"gps":{"latitude":-180,"longitude":180}};

至于键名可以随意。

地理空间查询以两种方式进行,即普通查询或者使用数据库命令。find的方式与一般的查询差别不大,只不过用了"$near"。需要两个目标值的数组作为参数:

db.map.find({"gps":{"$near":[40,-73]}})

这会按照离点(40,-73)由近及远的方式将map集合的所有文档都返回。在没有指定limit的值时,默认是100个文档。

也可以使用geoNear来完成相同操作。

db.runCommond({"geoNear”:"map","near":[40,-73]})

geoNear还会返回每个文档到查询点的距离,这个距离是以你插入的数据为单位的,如果按照经纬度的角度插入,则距离就是经纬度。

find和"$near"的组合不会给出距离,但若结果大于4M,这是唯一的选择。

MongoDB 学习五:索引的更多相关文章

  1. MongoDB学习笔记~索引提高查询效率

    回到目录 索引这个东西大家不会陌生,只要接触到稍微大一点的数据,都会用到这东西,它可以提升查询的速度,相当代价就是占用了更多的存储空间,这也是正常的,符合“能量守恒定理”,哈哈!今天说的是MongoD ...

  2. MongoDB学习笔记(索引)

    一.索引基础:    MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧.下面是创建索引的命令:    > db.test.ensureIndex({" ...

  3. MongoDB学习笔记(索引)(转)

    一.索引基础:    MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧.下面是创建索引的命令:    > db.test.ensureIndex({" ...

  4. MongoDB学习笔记——索引管理

    索引 索引能够提升查询的效率.没有索引,MongoDB必须扫描集合中的所有文档,才能找到匹配查询语句的文档. 索引是一种特殊的数据结构,将一小块数据集保存为容易遍历的形式.索引能够存储某种特殊字段或字 ...

  5. [转载]MongoDB学习 (五):查询操作符(Query Operators).1st

    本文地址:http://www.cnblogs.com/egger/archive/2013/05/04/3059374.html   欢迎转载 ,请保留此链接๑•́ ₃•̀๑! 查询操作符(Quer ...

  6. mongodb学习(六)索引

    准备工作: 先插入100万条数据 for(i=0;i<=1000000;i++){ db.users.insert({ "i":i, "username" ...

  7. MongoDB学习day08--Mongoose索引、Mongoose内置方法、扩展Mongoose Model的静态方法和实例方法

    一.Mongoose索引 索引是对数据库表中一列或多列的值进行排序的一种结构, 可以让我们查询数据库变得更快. MongoDB 的索引几乎与传统的关系型数据库一模一样, 这其中也包括一些基本的查询优化 ...

  8. mongodb学习(五) 查询

    1. 按条件查询: db.users.find({"name":"MM1"}) 2.find的第二个参数可以指定要返回的字段:这里1 表示要显示的字段,0 表示 ...

  9. MongoDB学习笔记系列

    回到占占推荐博客索引 该来的总会来的,Ef,Redis,MVC甚至Sqlserver都有了自己的系列,MongoDB没有理由不去整理一下,这个系列都是平时在项目开发时总结出来的,希望可以为各位一些帮助 ...

随机推荐

  1. python读取Excel实例

    1.操作步骤: (1)安装python官方Excel库-->xlrd (2)获取Excel文件位置并读取 (3)读取sheet (4)读取指定rows和cols内容 2.示例代码 # -*- c ...

  2. AC日记——[福利]可持久化线段树 cogs 2554

    2554. [福利]可持久化线段树 ★★☆   输入文件:longterm_segtree.in   输出文件:longterm_segtree.out   简单对比时间限制:3 s   内存限制:2 ...

  3. 理解webpack中的devTool的配置项

    2.1. eval  eval 会将每一个module模块,执行eval,执行后不会生成sourcemap文件,仅仅是在每一个模块后,增加sourceURL来关联模块处理前后对应的关系.在webpac ...

  4. RichEditControl(富文本控件)

    可以发邮 件??? https://ww w.evget.com/article/2014/3/25/20723.html

  5. Thread线程的基础知识及常见疑惑点

    引言 相信各位道友在平时工作中已经很少直接用到Thread线程类了,现在大多是通过线程池或者一些多线程框架来操作线程任务,但我觉得还是有必要了解清楚Thread线程类中各种方法的含义,了解了底层才能更 ...

  6. 洛谷——P2701 [USACO5.3]巨大的牛棚Big Barn

    P2701 [USACO5.3]巨大的牛棚Big Barn 题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他 ...

  7. BZOJ2527Meteors

    BZOJ2527 整体二分模板题 整体二分: 主要用于解决第K大问题 #include<cstdio> #include<cctype> #include<vector& ...

  8. linux内核I2C子系统学习(三)

    写设备驱动: 四部曲: 构建i2c_driver 注册i2c_driver 构建i2c_client ( 第一种方法:注册字符设备驱动.第二种方法:通过板文件的i2c_board_info填充,然后注 ...

  9. centos 升级内核失败回救

    在升级 centos6.3上使用, yum -y update  ... 灾难出现了!!! 解决方法: 1. 在机器启动的时候, 按F1, 会出现选择内核,选一个原来的. 2. vim /etc/gr ...

  10. AngularJS的ng-repeat显示属性名和属性值

    代码下载:https://files.cnblogs.com/files/xiandedanteng/AngularJSAuthorRepeat.rar 代码: <!DOCTYPE HTML P ...