mongodb可以通过profile来监控数据,进行优化,下列操作基于Studio 3T可视化工具,另外也可以通过自带的web管理界面进行操作或者是mongoDB自带的命令行工具mongostat。
1、查看当前mongoDB是否开启profile功能,
使用命令:db.getProfilingLevel();返回level等级,值为0|1|2,分别代表意思:0代表关闭,1代表记录慢命令,2代表全部。通常没做过任何修改的默认是返回0,也就是关闭状态。
使用命令:db.setProfilingLevel(level);开启profile功能为,其中level为1的时候,慢命令默认值为100ms,更改为db.setProfilingLevel(level,slowms)如db.setProfilingLevel(1,50)这样就更改为50毫秒,取决于你的需求自行调整。
通过上述设置后,我们先执行下面一条简单查询语句,因为之前的执行语句在没有开启profile功能时是查询不出监控日志的
db.getCollection("_mongoCase").find({_id:ObjectId("5c0c70747d9c6f0728933388")});
2、查看当前执行过的命令的监控日志
使用命令:db.system.profile.find() 查看当前所有的监控日志。当然我们也可以通过执行db.system.profile.find({millis:{$gt:500}})能够返回查询时间在500毫秒以上的查询命令。总之find里面的条件可以根据你当前的需要进行更改。
示例:执行命令 db.system.profile.find({millis:{$lt:1}}); 返回监控日志如下:
{
"op" : "query", //操作类型,有insert、query、update、remove、getmore、command
"ns" : "test._mongoCase", //命令空间,哪个库下的哪个集合
"command" : { //执行的命令
"find" : "_mongoCase", //目标对象集合
"filter" : { //过滤条件
"_id" : ObjectId("5c0c70747d9c6f0728933388")
},
"batchSize" : 33350.0,
"$db" : "test", //数据库
"lsid" : {
"id" : BinData(4, "XA2BHNiqTau9J278WRS3sA==")
},
"$readPreference" : {
"mode" : "secondaryPreferred"
}
},
"keysExamined" : 1.0, //索引扫描数量,这里用了_id,所以是1,如果没有用主键或索引这里会是0
"docsExamined" : 1.0, //文档扫描数量
"cursorExhausted" : true,
"numYield" : 0.0, //该操作为了使其他操作完成而放弃的次数。通常来说,当他们需要访问 还没有完全读入内存中的数据时,操作将放弃。这使得在MongoDB为了 放弃操作进行数据读取的同时,还有数据在内存中的其他操作可以完成。
"nreturned" : 1.0, //返回的文档数量
"locks" : { //锁信息,R:全局读锁;W:全局写锁;r:特定数据库的读锁;w:特定数据库的写锁
"Global" : { //全局锁
"acquireCount" : {
"r" : NumberLong(1) //该操作获取一个全局级锁花费的时间
}
},
"Database" : { //数据库锁
"acquireCount" : {
"r" : NumberLong(1)
}
},
"Collection" : { //集合锁
"acquireCount" : {
"r" : NumberLong(1)
}
}
},
"responseLength" : 258.0, //返回结果字节长度
"protocol" : "op_msg",
"millis" : 0.0, //消耗的时间(毫秒)
"planSummary" : "IDHACK", //执行概览 从这里看来 是主键查询,COLLSCAN 为全文档扫描
"execStats" : { //详细的执行计划 这里先略过 后续可以用 explain来具体分析
"stage" : "IDHACK",
"nReturned" : 1.0,
"executionTimeMillisEstimate" : 0.0,
"works" : 2.0,
"advanced" : 1.0,
"needTime" : 0.0,
"needYield" : 0.0,
"saveState" : 0.0,
"restoreState" : 0.0,
"isEOF" : 1.0,
"invalidates" : 0.0,
"keysExamined" : 1.0,
"docsExamined" : 1.0
},
"ts" : ISODate("2018-12-16T03:56:54.206+0000"), //命令执行的时间
"client" : "127.0.0.1", //访问的主机
"allUsers" : [
],
"user" : ""
}
慢查询的分析参考:
-
如果发现 millis 值比较大,那么就需要作优化。
-
如果docsExamined数很大,或者接近记录总数(文档数),那么可能没有用到索引查询,而是全表扫描。
-
如果keysExamined数为0,也可能是没用索引。
-
结合 planSummary 中的显示,上例中是 "IDHACK" 确认是针对主键查询,因为id是默认主键
-
如果 keysExamined 值高于 nreturned 的值,说明数据库为了找到目标文档扫描了很多文档。这时可以考虑创建索引来提高效率。
-
索引的键值选择可以根据 query 中的输出参考,
-
分析具体的执行计划,使用命令 db.getCollection("_mongoCase").find({_id:ObjectId("5c0c70747d9c6f0728933388")}).explain(); 这种操作类似于PL/SQL的F5。
3、查看某一个db的运行状态
使用命令 db.stats();能够查看当前数据库的运行情况
{
"db" : "test", //库名
"collections" : 2.0, //集合数
"views" : 0.0,
"objects" : 17.0, //记录数
"avgObjSize" : 336.5882352941176, //每条记录的平均值
"dataSize" : 5722.0, //记录的总大小
"storageSize" : 73728.0, //预分配的存储空间
"numExtents" : 0.0, //事件数
"indexes" : 1.0, //索引数
"indexSize" : 16384.0, //索引大小
"fsUsedSize" : 18770034688.0, //文件使用大小
"fsTotalSize" : 304943722496.0, //文件总大小
"ok" : 1.0
}
4、查看mongoDB运行状态
使用命令 db.serverStatus();能够查询这个mongoDB的运行情况
{
"host" : "DESKTOP-MFL4IGI", //主机名
"version" : "4.0.4", //mongoDB版本号
"process" : "E:\\MongoDB\\bin\\mongod.exe", //进程名
"pid" : NumberLong(12292), //进程ID
"uptime" : 7461.0, //运行时间
"uptimeMillis" : NumberLong(7460411),
"uptimeEstimate" : NumberLong(7460),
"localTime" : ISODate("2018-12-16T04:44:07.149+0000"), //当前时间
"asserts" : {
"regular" : 0.0,
"warning" : 0.0,
"msg" : 0.0,
"user" : 24.0,
"rollovers" : 0.0
},
"connections" : {
"current" : 4.0,
"available" : 999996.0,
"totalCreated" : 4.0
},
"extra_info" : {
"note" : "fields vary by platform",
"page_faults" : 52261.0,
"usagePageFileMB" : 149.0,
"totalPageFileMB" : 8998.0,
"availPageFileMB" : 3423.0,
"ramMB" : 8102.0
},
"freeMonitoring" : {
"state" : "undecided"
},
"globalLock" : {
"totalTime" : NumberLong(7460400000),
"currentQueue" : {
"total" : 0.0,
"readers" : 0.0,
"writers" : 0.0
},
"activeClients" : {
"total" : 15.0,
"readers" : 0.0,
"writers" : 0.0
}
},
"locks" : {
"Global" : {
"acquireCount" : {
"r" : NumberLong(24997),
"w" : NumberLong(205),
"W" : NumberLong(5)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(8635),
"w" : NumberLong(197),
"R" : NumberLong(10),
"W" : NumberLong(8)
},
"acquireWaitCount" : {
"W" : NumberLong(1)
},
"timeAcquiringMicros" : {
"W" : NumberLong(171)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(8544),
"w" : NumberLong(172)
}
},
"Metadata" : {
"acquireCount" : {
"W" : NumberLong(9)
}
}
},
"logicalSessionRecordCache" : {
"activeSessionsCount" : 1.0,
"sessionsCollectionJobCount" : 25.0,
"lastSessionsCollectionJobDurationMillis" : 0.0,
"lastSessionsCollectionJobTimestamp" : ISODate("2018-12-16T04:39:48.942+0000"),
"lastSessionsCollectionJobEntriesRefreshed" : 0.0,
"lastSessionsCollectionJobEntriesEnded" : 0.0,
"lastSessionsCollectionJobCursorsClosed" : 0.0,
"transactionReaperJobCount" : 0.0,
"lastTransactionReaperJobDurationMillis" : 0.0,
"lastTransactionReaperJobTimestamp" : ISODate("2018-12-16T02:39:48.935+0000"),
"lastTransactionReaperJobEntriesCleanedUp" : 0.0
},
"network" : {
"bytesIn" : NumberLong(71202),
"bytesOut" : NumberLong(936059),
"physicalBytesIn" : NumberLong(71202),
"physicalBytesOut" : NumberLong(936059),
"numRequests" : NumberLong(1046),
"compression" : {
"snappy" : {
"compressor" : {
"bytesIn" : NumberLong(0),
"bytesOut" : NumberLong(0)