一、监控

mongodb可以通过profile来监控数据,进行优化。

查看当前是否开启profile功能用命令:db.getProfilingLevel()返回level等级,值为0|1|2,分别代表意思:0代表关闭,1代表记录慢命令,2代表全部。

开始profile功能为db.setProfilingLevel(level);

level为1的时候,慢命令默认值为100ms,更改为db.setProfilingLevel(level,slowms)如db.setProfilingLevel(1,50)这样就更改为50毫秒

通过db.system.profile.find() 查看当前的监控日志。

通过执行db.system.profile.find({millis:{$gt:500}})能够返回查询时间在500毫秒以上的查询命令。

这里值的含义是

ts:命令执行时间
info:命令的内容
query:代表查询
order.order: 代表查询的库与集合
reslen:返回的结果集大小,byte数
nscanned:扫描记录数量
nquery:后面是查询条件
nreturned:返回记录数及用时
millis:所花时间

如果发现时间比较长,那么就需要作优化。

比如nscanned数很大,或者接近记录总数,那么可能没有用到索引查询。

reslen很大,有可能返回没必要的字段。

nreturned很大,那么有可能查询的时候没有加限制。

mongo可以通过db.serverStatus()查看mongod的运行状态

二、索引

首选就是为待查询的字段建立索引,不过需要特别注意的是,索引不是万能灵药。如果需要查询超过一半的集合数据,索引还不如直接遍历来的好。

索引的原理是通过建立指定字段的B树,通过搜索B树来查找对应document的地址。这也就解释了如果需要查询超过一半的集合数据,直接遍历省去了搜索B树的过程,效率反而会高。

关于索引,索引列颗粒越小越好,什么叫颗粒越小越好?在索引列中每个数据的重复数量称为颗粒,也叫作索引的基数。如果数据的颗粒过大,索引就无法发挥该有的性能。例如,我们拥有一个"age"列索引,如果在"age"列中,20岁占了50%,如果现在要查询一个20岁,名叫"Tom"的人,我们则需要在表的50%的数据中查询,索引的作用大大降低。所以,我们在建立索引时要尽量将数据颗粒小的列放在索引左侧,以保证索引发挥最大的作用。

由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。

索引不能被以下的查询使用:

  • 正则表达式及非操作符,如 $nin, $not, 等
  • 算术运算符,如 $mod, 等
  • $where 子句

三、explain

explain有三种模式,分别是:queryPlanner、executionStats、allPlansExecution:

queryPlanner:不会真正的执行查询,只是分析查询,选出winning plan。

executionStats:返回winning plan的关键数据,executionTimeMillis表示该query查询的总体时间。

allPlansExecution:执行所有的plans。

通常是使用 executionStats 模式
  1. MongoDB Enterprise > db.batch_info_201903.find({"phone":"","uuid":""}).explain("executionStats")
  2. {
  3. "queryPlanner" : {
  4. "plannerVersion" : ,
  5. "namespace" : "sms.batch_info_201903",
  6. "indexFilterSet" : false,
  7. "parsedQuery" : {
  8. "$and" : [
  9. {
  10. "phone" : {
  11. "$eq" : ""
  12. }
  13. },
  14. {
  15. "uuid" : {
  16. "$eq" : ""
  17. }
  18. }
  19. ]
  20. },
  21. "winningPlan" : {
  22. "stage" : "FETCH",
  23. "inputStage" : {
  24. "stage" : "IXSCAN",
  25. "keyPattern" : {
  26. "phone" : ,
  27. "uuid" :
  28. },
  29. "indexName" : "phone_1_uuid_1",
  30. "isMultiKey" : false,
  31. "isUnique" : false,
  32. "isSparse" : false,
  33. "isPartial" : false,
  34. "indexVersion" : ,
  35. "direction" : "forward",
  36. "indexBounds" : {
  37. "phone" : [
  38. "[\"13631277247\", \"13631277247\"]"
  39. ],
  40. "uuid" : [
  41. "[\"123\", \"123\"]"
  42. ]
  43. }
  44. }
  45. },
  46. "rejectedPlans" : [ ]
  47. },
  48. "executionStats" : {
  49. "executionSuccess" : true,
  50. "nReturned" : ,
  51. "executionTimeMillis" : ,
  52. "totalKeysExamined" : ,
  53. "totalDocsExamined" : ,
  54. "executionStages" : {
  55. "stage" : "FETCH",
  56. "nReturned" : ,
  57. "executionTimeMillisEstimate" : ,
  58. "works" : ,
  59. "advanced" : ,
  60. "needTime" : ,
  61. "needYield" : ,
  62. "saveState" : ,
  63. "restoreState" : ,
  64. "isEOF" : ,
  65. "invalidates" : ,
  66. "docsExamined" : ,
  67. "alreadyHasObj" : ,
  68. "inputStage" : {
  69. "stage" : "IXSCAN",
  70. "nReturned" : ,
  71. "executionTimeMillisEstimate" : ,
  72. "works" : ,
  73. "advanced" : ,
  74. "needTime" : ,
  75. "needYield" : ,
  76. "saveState" : ,
  77. "restoreState" : ,
  78. "isEOF" : ,
  79. "invalidates" : ,
  80. "keyPattern" : {
  81. "phone" : ,
  82. "uuid" :
  83. },
  84. "indexName" : "phone_1_uuid_1",
  85. "isMultiKey" : false,
  86. "isUnique" : false,
  87. "isSparse" : false,
  88. "isPartial" : false,
  89. "indexVersion" : ,
  90. "direction" : "forward",
  91. "indexBounds" : {
  92. "phone" : [
  93. "[\"13631277247\", \"13631277247\"]"
  94. ],
  95. "uuid" : [
  96. "[\"123\", \"123\"]"
  97. ]
  98. },
  99. "keysExamined" : ,
  100. "dupsTested" : ,
  101. "dupsDropped" : ,
  102. "seenInvalidated" :
  103. }
  104. }
  105. },
  106. "serverInfo" : {
  107. "host" : "develop",
  108. "port" : ,
  109. "version" : "3.2.11",
  110. "gitVersion" : "009580ad490190ba33d1c6253ebd8d91808923e4"
  111. },
  112. "ok" :
  113. }

对queryPlanner分析

queryPlanner: queryPlanner的返回

queryPlanner.namespace:该值返回的是该query所查询的表

queryPlanner.indexFilterSet:针对该query是否有indexfilter

queryPlanner.winningPlan:查询优化器针对该query所返回的最优执行计划的详细内容。

queryPlanner.winningPlan.stage:最优执行计划的stage,这里返回是FETCH,可以理解为通过返回的index位置去检索具体的文档(stage有数个模式,将在后文中进行详解)。

queryPlanner.winningPlan.inputStage:用来描述子stage,并且为其父stage提供文档和索引关键字。

queryPlanner.winningPlan.stage的child stage,此处是IXSCAN,表示进行的是index scanning。

queryPlanner.winningPlan.keyPattern:所扫描的index内容,此处是did:1,status:1,modify_time: -1与scid : 1

queryPlanner.winningPlan.indexName:winning plan所选用的index。

queryPlanner.winningPlan.isMultiKey是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true。

queryPlanner.winningPlan.direction:此query的查询顺序,此处是forward,如果用了.sort({modify_time:-1})将显示backward。

queryPlanner.winningPlan.indexBounds:winningplan所扫描的索引范围,如果没有制定范围就是[MaxKey, MinKey],这主要是直接定位到mongodb的chunck中去查找数据,加快数据读取。

queryPlanner.rejectedPlans:其他执行计划(非最优而被查询优化器reject的)的详细返回,其中具体信息与winningPlan的返回中意义相同,故不在此赘述。

对executionStats返回逐层分析

    第一层,executionTimeMillis

最为直观explain返回值是executionTimeMillis值,指的是我们这条语句的执行时间,这个值当然是希望越少越好。

其中有3个executionTimeMillis,分别是:

executionStats.executionTimeMillis

该query的整体查询时间。

executionStats.executionStages.executionTimeMillisEstimate

该查询根据index去检索document获得2001条数据的时间。

executionStats.executionStages.inputStage.executionTimeMillisEstimate

该查询扫描2001行index所用时间。

第二层,index与document扫描数与查询返回条目数

这个主要讨论3个返回项,nReturned、totalKeysExamined、totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目、文档扫描条目。

这些都是直观地影响到executionTimeMillis,我们需要扫描的越少速度越快。

对于一个查询,我们最理想的状态是:

nReturned=totalKeysExamined=totalDocsExamined

第三层,stage状态分析

那么又是什么影响到了totalKeysExamined和totalDocsExamined?是stage的类型。类型列举如下:

COLLSCAN:全表扫描

IXSCAN:索引扫描

FETCH:根据索引去检索指定document

SHARD_MERGE:将各个分片返回数据进行merge

SORT:表明在内存中进行了排序

LIMIT:使用limit限制返回数

SKIP:使用skip进行跳过

IDHACK:针对_id进行查询

SHARDING_FILTER:通过mongos对分片数据进行查询

COUNT:利用db.coll.explain().count()之类进行count运算

COUNTSCAN:count不使用Index进行count时的stage返回

COUNT_SCAN:count使用了Index进行count时的stage返回

SUBPLA:未使用到索引的$or查询的stage返回

TEXT:使用全文索引进行查询时候的stage返回

PROJECTION:限定返回字段时候stage的返回

对于普通查询,我希望看到stage的组合(查询的时候尽可能用上索引):

Fetch+IDHACK

Fetch+ixscan

Limit+(Fetch+ixscan)

PROJECTION+ixscan

SHARDING_FITER+ixscan

COUNT_SCAN

不希望看到包含如下的stage:

COLLSCAN(全表扫描),SORT(使用sort但是无index),不合理的SKIP,SUBPLA(未用到index的$or),COUNTSCAN(不使用index进行count)

四、设计优化

如果是插入频繁,修改多,查询较少的,可利用数据库的范式形式保存数据:

  1. {
  2. "_id" : ObjectId("5124b5d86041c7dca81917"),
  3. "title" : "如何使用MongoDB",
  4. "author" : [
  5. ObjectId("144b5d83041c7dca84416"),
  6. ObjectId("144b5d83041c7dca84418"),
  7. ObjectId("144b5d83041c7dca84420"),
  8. ]
  9. }

如果是查询频繁,插入修改较少的,可以全部内嵌来设计:

  1. {
  2. "_id" : ObjectId("5124b5d86041c7dca81917"),
  3. "title" : "如何使用MongoDB",
  4. "author" : [
  5. {
  6.      "name" : "丁磊"
  7.      "age" : ,
  8.     "nationality" : "china",
  9. },
  10. {
  11.      "name" : "马云"
  12.      "age" : ,
  13.      "nationality" : "china",
  14. },
  15. {
  16.      "name" : "张召忠"
  17.      "age" : ,
  18.      "nationality" : "china",
  19. },
  20. ]
  21. }

折中设计,但是需要考虑到实际业务进行结合来寻找合适的提取字段:

  1. {
  2. "_id" : ObjectId("5124b5d86041c7dca81917"),
  3. "title" : "如何使用MongoDB",
  4. "author" : [
  5. {
  6.     "_id" : ObjectId("144b5d83041c7dca84416"),
  7.      "name" : "丁磊"
  8. },
  9. {
  10.      "_id" : ObjectId("144b5d83041c7dca84418"),
  11.      "name" : "马云"
  12. },
  13. {
  14.      "_id" : ObjectId("144b5d83041c7dca84420"),
  15.      "name" : "张召忠"
  16. },
  17. ]
  18. }

五、字段

1、可为不想保存历史数据但又不想删除过多数据的集合添加过期索引,索引可加上过期时间或不添加,插入数据时可在指定字段确定是否添加过期时间

2、组合使用

六、其他

热数据法

可能你的数据集非常大,但是这并不那么重要,重要的是你的热数据集有多大,你经常访问的数据有多大(包括经常访问的数据和所有索引数据)。使用MongoDB,你最好保证你的热数据在你机器的内存大小之下,保证内存能容纳所有热数据。

文件系统法

MongoDB的数据文件是采用的预分配模式,并且在Replication里面,Master和Replica Sets的非Arbiter节点都是会预先创建足够的空文件用以存储操作日志。这些文件分配操作在一些文件系统上可能会非常慢,导致进程被Block。所以我们应该选择那些空间分配快速的文件系统。这里的结论是尽量不要用ext3,用ext4或者xfs。

硬件法

这里的选择包括了对磁盘RAID的选择,也包括了磁盘与SSD的对比选择

七、数据存储方式

1、主从,primary-secondary

2、分片,shard

MongoDB使用优化的更多相关文章

  1. MongoDB 性能优化五个简单步骤

    MongoDB 一直是最流行的 NoSQL,而根据 DB-Engines Ranking 最新的排行,时下 MongoDB 已经击败 PostgreSQL 跃居数据库总排行的第四位,仅次于 Oracl ...

  2. mongodb可以通过profile来监控数据 (mongodb性能优化)

    mongodb可以通过profile来监控数据 (mongodb性能优化)   开启 Profiling  功能 ,对慢查询进行优化: mongodb可以通过profile来监控数据,进行优化. 查看 ...

  3. MongoDB性能优化

    一.索引 MongoDB 提供了多样性的索引支持,索引信息被保存在system.indexes 中,且默认总是为_id创建索引,它的索引使用基本和MySQL 等关系型数据库一样.其实可以这样说说,索引 ...

  4. MongoDB性能优化指南

    一.索引 MongoDB 提供了多样性的索引支持,索引信息被保存在system.indexes 中,且默认总是为_id创建索引,它的索引使用基本和MySQL 等关系型数据库一样.其实可以这样说说,索引 ...

  5. mongodb分页优化

    现在参与一个项目的开发,需要用java查询mongodb数据库,在这里分页用的skip sort 和limit结合,查询语句如下(已经在相关字段建立索引) DBCursor cursor = coll ...

  6. jemalloc Mongodb Nginx 优化

    下载 http://www.canonware.com/jemalloc/download.html 下载 wget http://www.canonware.com/download/jemallo ...

  7. mongodb 参数优化

    1.大部分IO操作为随机IO,建议采用SSD或PCIE,普通硬盘RAID10 2.IO调度算法.普通磁盘:deadline避免IO请求出现“饥饿”现象,SSD/PCIE:noop简单的先进先出处理请求 ...

  8. 开发高性能的MongoDB应用—浅谈MongoDB性能优化(转)

    出处:http://www.cnblogs.com/mokafamily/p/4102829.html 性能与用户量 “如何能让软件拥有更高的性能?”,我想这是一个大部分开发者都思考过的问题.性能往往 ...

  9. 开发高性能的MongoDB应用—浅谈MongoDB性能优化

    关联文章索引: 大数据时代的数据存储,非关系型数据库MongoDB 性能与用户量 “如何能让软件拥有更高的性能?”,我想这是一个大部分开发者都思考过的问题.性能往往决定了一个软件的质量,如果你开发的是 ...

随机推荐

  1. redis 3.2.1 centos7

    设置外网访问 vmare:centos7redis:3.2.1 redis-cli shutdown 重启./redis-server 启动服务 启动之后无法访问 cd redis-3.2.1 vim ...

  2. swap的实现(没有中间变量)

    两数交换最常用的方法 void swap(int &a,int &b) { int temp=a; a=b; b=temp; } 如果没有中间变量temp可以使用呢,还有其他的三种方法 ...

  3. tornado框架学习及借用有道翻译api做自动翻译页面

    趁着这几天有时间,就简单的学了一下tornado框架,简单做了个自动翻译的页面 仅为自己学习参考,不作其他用途 文件夹目录结构如下: . ├── server.py ├── static │   └─ ...

  4. maven pom.xml文件 仓库搜索服务

    POM(Project Object Model),即项目对象模型,是 Maven 工程的基本工作单元,是一个 XML 文件,包含了项目的基本信息,用于描述项目如何构建.声明项目依赖 等等 Maven ...

  5. JVM 字节码(一)字节码规范

    JVM 字节码(一)字节码规范 JVM 学习资源 Java ClassFile 字节码规范(Oracle) Java 虚拟机规范(Java SE 7 中文版) (周志明等译) Java 反编译工具 - ...

  6. 别人的Linux私房菜(11)认识与学习BASH

    Linux下使用BASH   Bourne Again Shell        另外一种由用于Unix的伯克利大学的Bill Joy设计的C Shell 系统中合法的shell会写入到/etc/sh ...

  7. c++WIN32获取syslistview行数

    #include "stdafx.h" #include <windows.h> #include <commctrl.h> #include <io ...

  8. telnet的安装和使用

    在日常使用中,有时候需要检测服务器上面的部分端口有没有打开,这个时候可以使用telnet进行调试.下面是一篇转载的文章. 原文地址:http://linuxtech.blog.51cto.com/36 ...

  9. k-th smallest 问题总结

    k-th smallest/biggest 问题大约有这几道: 373. Find K Pairs with Smallest Sums 从两个list里各取一个数求和,求所有可能的sum里第k小的 ...

  10. AngularJS封装webupload实现文件夹上传

    百度的webupload没有开放api获取整个文件夹的信息.本文是二次开发webupload实现获取文件夹信息. 指令封装 /** * @license lx.ui.framework v1.0.0 ...