复合索引 <接上>

> 删除之前的collection,重新建立,如下所示:

> db.person.drop()

true

> for(var i=0;i<2000000;i++){

... db.person.insert({"name":"meteor"+i%1000,"age":20+i%10});

... }

WriteResult({ "nInserted" : 1 })

>

> db.person.ensureIndex({"age":1})        创建单一索引

{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}

> db.person.ensureIndex({"name":1,"age":1})    创建复合索引 {"name":1,"age":1}

{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}

> db.person.ensureIndex({"age":1,"name":1})        创建复合索引{"age":1,"name":1}

{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 3,
"numIndexesAfter" : 4,
"ok" : 1
}

> 查找时指定多个条件,使用hint强制指定使用单一索引速度比较慢,如下所示:

> db.person.find({"age":{"$gte":20,"$lte":30},"name":"meteor1"}).hint({"age":1}).explain("executionStats")

{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.person",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"name" : {
"$eq" : "meteor1"
}
},
{
"age" : {
"$lte" : 30
}
},
{
"age" : {
"$gte" : 20
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"name" : {
"$eq" : "meteor1"
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"age" : 1
},
"indexName" : "age_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"age" : [
"[20.0, 30.0]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 2000,
"executionTimeMillis" : 2621,
"totalKeysExamined" : 2000000,
"totalDocsExamined" : 2000000,
"executionStages" : {
"stage" : "FETCH",
"filter" : {
"name" : {
"$eq" : "meteor1"
}
},
"nReturned" : 2000,
"executionTimeMillisEstimate" : 2050,
"works" : 2000001,
"advanced" : 2000,
"needTime" : 1998000,
"needYield" : 0,
"saveState" : 15625,
"restoreState" : 15625,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 2000000,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 2000000,
"executionTimeMillisEstimate" : 640,
"works" : 2000001,
"advanced" : 2000000,
"needTime" : 0,
"needYield" : 0,
"saveState" : 15625,
"restoreState" : 15625,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"age" : 1
},
"indexName" : "age_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"age" : [
"[20.0, 30.0]"
]
},
"keysExamined" : 2000000,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"serverInfo" : {
"host" : "meteor.yeecall.com",
"port" : 27027,
"version" : "3.2.8",
"gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0"
},
"ok" : 1
}

> 查找数据时指定多个条件,使用hint强制指定使用{"age":1,"name":1}复合索引,速度比较快,如下所示:

> db.person.find({"age":{"$gte":20,"$lte":30},"name":"meteor1"}).hint({"age":1,"name":1}).explain("executionStats")

{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.person",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"name" : {
"$eq" : "meteor1"
}
},
{
"age" : {
"$lte" : 30
}
},
{
"age" : {
"$gte" : 20
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"age" : 1,
"name" : 1
},
"indexName" : "age_1_name_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"age" : [
"[20.0, 30.0]"
],
"name" : [
"[\"meteor1\", \"meteor1\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 2000,
"executionTimeMillis" : 15,
"totalKeysExamined" : 2010,
"totalDocsExamined" : 2000,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 2000,
"executionTimeMillisEstimate" : 10,
"works" : 2011,
"advanced" : 2000,
"needTime" : 10,
"needYield" : 0,
"saveState" : 15,
"restoreState" : 15,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 2000,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 2000,
"executionTimeMillisEstimate" : 10,
"works" : 2011,
"advanced" : 2000,
"needTime" : 10,
"needYield" : 0,
"saveState" : 15,
"restoreState" : 15,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"age" : 1,
"name" : 1
},
"indexName" : "age_1_name_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"age" : [
"[20.0, 30.0]"
],
"name" : [
"[\"meteor1\", \"meteor1\"]"
]
},
"keysExamined" : 2010,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"serverInfo" : {
"host" : "meteor.yeecall.com",
"port" : 27027,
"version" : "3.2.8",
"gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0"
},
"ok" : 1
}

=================================================================================

查询结束再次排序(按name排序),并使用limit截取其中一部分,使用hint强制指定使用{"age":1,"name":1}索引时速度较慢,如下所示:

> db.person.find({"age":{"$gte":20,"$lte":30}}).sort({"name":1}).limit(100).hint({"age":1,"name":1}).explain("executionStats")

{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.person",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"age" : {
"$lte" : 30
}
},
{
"age" : {
"$gte" : 20
}
}
]
},
"winningPlan" : {
"stage" : "SORT",
"sortPattern" : {
"name" : 1
},
"limitAmount" : 100,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"age" : 1,
"name" : 1
},
"indexName" : "age_1_name_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"age" : [
"[20.0, 30.0]"
],
"name" : [
"[MinKey, MaxKey]"
]
}
}
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 100,
"executionTimeMillis" : 6991,
"totalKeysExamined" : 2000000,
"totalDocsExamined" : 2000000,
"executionStages" : {
"stage" : "SORT",
"nReturned" : 100,
"executionTimeMillisEstimate" : 5980,
"works" : 2000103,
"advanced" : 100,
"needTime" : 2000002,
"needYield" : 0,
"saveState" : 15625,
"restoreState" : 15625,
"isEOF" : 1,
"invalidates" : 0,
"sortPattern" : {
"name" : 1
},
"memUsage" : 6100,
"memLimit" : 33554432,
"limitAmount" : 100,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"nReturned" : 0,
"executionTimeMillisEstimate" : 5680,
"works" : 2000002,
"advanced" : 0,
"needTime" : 1,
"needYield" : 0,
"saveState" : 15625,
"restoreState" : 15625,
"isEOF" : 1,
"invalidates" : 0,
"inputStage" : {
"stage" : "FETCH",
"nReturned" : 2000000,
"executionTimeMillisEstimate" : 4870,
"works" : 2000001,
"advanced" : 2000000,
"needTime" : 0,
"needYield" : 0,
"saveState" : 15625,
"restoreState" : 15625,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 2000000,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 2000000,
"executionTimeMillisEstimate" : 2400,
"works" : 2000001,
"advanced" : 2000000,
"needTime" : 0,
"needYield" : 0,
"saveState" : 15625,
"restoreState" : 15625,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"age" : 1,
"name" : 1
},
"indexName" : "age_1_name_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"age" : [
"[20.0, 30.0]"
],
"name" : [
"[MinKey, MaxKey]"
]
},
"keysExamined" : 2000000,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
}
},
"serverInfo" : {
"host" : "meteor.yeecall.com",
"port" : 27027,
"version" : "3.2.8",
"gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0"
},
"ok" : 1
}
>

查询结束再次排序(按name排序),并使用limit截取其中一部分,使用hint强制指定使用{"name":1,"age":1}索引时速度较快,如下所示:

> db.person.find({"age":{"$gte":20,"$lte":30}}).sort({"name":1}).limit(100).hint({"name":1,"age":1}).explain("executionStats")

{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.person",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"age" : {
"$lte" : 30
}
},
{
"age" : {
"$gte" : 20
}
}
]
},
"winningPlan" : {
"stage" : "LIMIT",
"limitAmount" : 100,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"age" : {
"$lte" : 30
}
},
{
"age" : {
"$gte" : 20
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"name" : 1,
"age" : 1
},
"indexName" : "name_1_age_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"name" : [
"[MinKey, MaxKey]"
],
"age" : [
"[MinKey, MaxKey]"
]
}
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 100,
"executionTimeMillis" : 5,
"totalKeysExamined" : 100,
"totalDocsExamined" : 100,
"executionStages" : {
"stage" : "LIMIT",
"nReturned" : 100,
"executionTimeMillisEstimate" : 0,
"works" : 101,
"advanced" : 100,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"limitAmount" : 100,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"age" : {
"$lte" : 30
}
},
{
"age" : {
"$gte" : 20
}
}
]
},
"nReturned" : 100,
"executionTimeMillisEstimate" : 0,
"works" : 100,
"advanced" : 100,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 0,
"invalidates" : 0,
"docsExamined" : 100,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 100,
"executionTimeMillisEstimate" : 0,
"works" : 100,
"advanced" : 100,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 0,
"invalidates" : 0,
"keyPattern" : {
"name" : 1,
"age" : 1
},
"indexName" : "name_1_age_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"name" : [
"[MinKey, MaxKey]"
],
"age" : [
"[MinKey, MaxKey]"
]
},
"keysExamined" : 100,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
},
"serverInfo" : {
"host" : "meteor.yeecall.com",
"port" : 27027,
"version" : "3.2.8",
"gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0"
},
"ok" : 1
}

>       如果按age排序,索引使用{"name":1,"age":1}速度非常慢;如果按age排序,索引使用{"age":1,"name":1}速度比较快

>分析:第一种索引,需要找到所有复合查询条件的值(依据索引,键和文档可以快速找到),但是找到后,需要对文档在内存中进行排序,这个步骤消耗了非常多的时间。第二种索引,效果非常好,因为不需要在内存中对大量数据进行排序。但是,MongoDB不得不扫描整个索引以便找到所有文档。因此,如果对查询结果的范围做了限制,那么MongoDB在几次匹配之后就可以不再扫描索引,在这种情况下,将排序键放在第一位是一个非常好的策略。

查看索引 

> db.person.getIndexes()

[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.person"
},
{
"v" : 1,
"key" : {
"age" : 1
},
"name" : "age_1",
"ns" : "test.person"
},
{
"v" : 1,
"key" : {
"name" : 1,
"age" : 1
},
"name" : "name_1_age_1",
"ns" : "test.person"
},
{
"v" : 1,
"key" : {
"age" : 1,
"name" : 1
},
"name" : "age_1_name_1",
"ns" : "test.person"
}
]

> db.person.dropIndex("name_1_age_1")        删除索引

{ "nIndexesWas" : 4, "ok" : 1 }

> db.person.dropIndex("age_1_name_1")

{ "nIndexesWas" : 3, "ok" : 1 }

> db.person.dropIndex("age_1")

{ "nIndexesWas" : 2, "ok" : 1 }

> db.runCommand({dropIndexes:"person",index:"*"})        删除索引的另一种方法

{
"nIndexesWas" : 1,
"msg" : "non-_id indexes dropped for collection",
"ok" : 1
}

> db.person.ensureIndex({"name":1,"age":1},{"unique":true})    创建唯一索引 (本例没有成功,因为集合中有重复内容)

{
"ok" : 0,
"errmsg" : "E11000 duplicate key error collection: test.person index: name_1_age_1 dup key: { : \"meteor0\", : 20.0 }",
"code" : 11000
}

MongoDB 索引限制

额外开销

每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。所以,如果你很少对集合进行读取操作,建议不使用索引。

内存(RAM)使用

由于索引是存储在内存(RAM)中,应该确保该索引的大小不超过内存的限制。(如上文中提示sort排序后,如果没有limit字段系统会提示错误,因为索引大小超过了内存的限制)

如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。

查询限制

索引不能被以下的查询使用:正则表达式及非操作符,如 $nin, $not, 等;算术运算符,如 $mod, 等;$where 子句

所以,检测语句是否使用索引是一个好的习惯,可以用explain来查看。

索引键限制

从2.6版本开始,如果现有的索引字段的值超过索引键的限制,MongoDB中不会创建索引。

插入文档超过索引键限制

如果文档的索引字段值超过了索引键的限制,MongoDB不会将任何文档转换成索引的集合。与mongorestore和mongoimport工具类似。

最大范围

集合中索引不能超过64个;索引名的长度不能超过125个字符

一个复合索引最多可以有31个字段

转载于:https://blog.51cto.com/caiyuanji/1836615

mongodb Index(2)相关推荐

  1. mongodb Index(3)

    全文索引 MongoDB有一个特殊的索引用在文档中搜索文本,之前的博客都是用精确匹配来查询字符串,这些技术有一定的限制.在搜索大块文本的速度非常慢,而且无法处理自然语言礼节的问题.全文本索引使用的是& ...

  2. 结合MongoDB开发LBS应用

    http://www.cnblogs.com/jifeng/p/4356052.html 然后列举一下需求: 1.实时性要高,有频繁的更新和读取 2.可按距离排序支持分页 3.支持多条件筛选(一个经纬 ...

  3. [Cacti] cacti监控mongodb性能实战

    前言: 为了更好的使用mongodb,须要监控出mongodb的一些基础使用情况,比方Flush数.连接数.内存使用率.Index操作.Slave延迟等等,这些能够通过配置cacti监控mongodb ...

  4. 结合MongoDB开发LBS应用(mongodb geo)

    简介 随着近几年各类移动终端的迅速普及,基于地理位置的服务(LBS)和相关应用也越来越多,而支撑这些应用的最基础技术之一,就是基于地理位置信息的处理.我所在的项目也正从事相关系统的开发,我们使用的是S ...

  5. 详解基于MongoDB的地理位置查询,结合Symfony2演示

    简介 随着近几年各类移动终端的迅速普及,基于地理位置的服务(LBS)和相关应用也越来越多,而支撑这些应用的最基础技术之一,就是基于地理位置信息的处理.我所在的项目也正从事相关系统的开发,我们使用的是S ...

  6. 2.windows安装mongodb企业版

    2.windows安装mongodb企业版 最新内容会在源站更新.转载请保留原文链接: http://dashidan.com/article/mongodb/index.html ① 下载Mongo ...

  7. 结合MongoDB开发LBS应用(转)

    原文链接:结合MongoDB开发LBS应用 简介 随着近几年各类移动终端的迅速普及,基于地理位置的服务(LBS)和相关应用也越来越多,而支撑这些应用的最基础技术之一,就是基于地理位置信息的处理.我所在 ...

  8. MongoDB-概述:跨平台的面向文档的高性能高可用性易扩展数据库

    Table of Contents MongoDB-概述 数据库 采集 文件 样本文件 MongoDB教程 MongoDB-优势 MongoDB与RDBMS相比的优势 为什么要使用MongoDB? 在 ...

  9. 后端存储实战-极客时间

    电商系统是如何设计的 不要一上来就设计功能 这个系统是给谁用的? 这些人用来该系统解决什么问题? 电商:用户.运营.报表 购物流程:浏览商品-----加购------下单-------支付------ ...

最新文章

  1. 大数据可视化html模板开源_5个最受工程师欢迎的大数据可视化工具
  2. Leetcode 191. 位1的个数 解题思路及C++实现
  3. gdb+pwndbg使用初探
  4. C# 程序执行时间差
  5. c语言 执行free函数程序被卡住,FreeRTOS操作系统,在按键中断函数中恢复被挂起的任务,程序卡死的原因和解决办法...
  6. 社区 正式发布了跨平台的 CoreWCF 0.1.0 GA
  7. k3 审核流程图_3-金蝶K3操作流程图详解
  8. C++ (tensorRT中学习)
  9. java 蓝桥杯 算法训练 区间k大数查询(题解)
  10. 学python要多久-python入门要学多久
  11. Linux文件夹操作
  12. 查看name的状态,是属于active还是standby
  13. python登陆qq邮箱_python+selenium自动化测试——QQ邮箱自动登录写信
  14. JAVA长方形正方形_正方形不是长方形的终极解决办法
  15. iOS设备踢出恢复模式的几种方法
  16. u盘变o字节怎么修复_U盘变成0字节了数据怎么恢复
  17. mfs网络分布式文件系统、高可用、iscsi存储方式的mfs、fence
  18. 吉里吉里1/吉里吉里2中KAG脚本的解释执行(1)
  19. Mac笔记本常用软件
  20. Linux部署IPFS(分布式存储系统)私有网络

热门文章

  1. 无可奈何花落去,七大没落软件排名
  2. 代账行业急需标准,良莠不齐成为过去!
  3. 倾斜摄影处理常用工具
  4. 今天告诉你音频剪切的方法有哪些
  5. 电脑书籍下载【申明:来源于网络】
  6. android app换肤Android-skin-support的简单使用
  7. EndNote两台电脑同步library
  8. GPS接收器相关的毕业论文有哪些呢?
  9. ubuntu 生成公钥_ubuntu 添加多个ssh公钥和私钥
  10. Android魔镜:方法耗时统计插件Mirror-基础篇