mongodb慢查询排查

本文介绍了如何开启和分析MongoDB的慢查询记录。通过检查was参数确认慢查询是否已开启,并说明了如何设置记录级别。同时,文章提到了通过观察system.profile表来查看慢查询详情,帮助用户定位和解决问题。

是否开启了慢查询记录

选择某一数据库,执行db.getProfilingStatus(),可得到如下结果:

was=1表示开启了慢查询记录,0表示未开启
showms表示记录超过多少ms的数据库操作


开启记录慢查询

开始方法有2种

只开启某一个数据库

选中某一数据库后,shell里执行db.setProfilingLevel(1,200),其中,参数1表示记录的级别,参数2表示记录大于多少ms的操作


 
  1. 0:关闭,不收集任何数据。
  2. 1:收集慢查询数据,默认是100毫秒。
  3. 2:收集所有数据

服务器上的所有数据库都开启


 
  1. #也可以MongoDB启动时,开启Profiling
  2. mongod --profile=1 --slowms=200
  3. #或者在配置文件里添加
  4. profile = 1
  5. slowms = 200

分析方法

查看system.profile表,里面会记录所有慢查询记录

其中一条的详细说明如下:


 
  1. #下面是一个超过200ms的查询语句
  2. {
  3. "op" : "query", #操作类型,有insert、query、update、remove、getmore、command
  4. "ns" : "F10data3.f10_2_8_3_jgcc",
  5. "query" : { #具体的查询语句 包括过滤条件,limit行数 排序字段
  6. filter" : {
  7. "jzrq" : {
  8. "$gte" : ISODate("2017-03-31T16:00:00.000+0000"),
  9. "$lte" : ISODate("2017-06-30T15:59:59.000+0000")
  10. },
  11. "jglxfldm" : 10.0
  12. },
  13. "ntoreturn" : 200.0,
  14. "sort" : { #如果有排序 则显示排序的字段 这里是 RsId
  15. "RsId" : 1.0
  16. }
  17. },
  18. "keysExamined" : 0.0, #索引扫描数量 这里是全表扫描,没有用索引 所以是 0
  19. "docsExamined" : 69608.0, #浏览的文档数 这里是全表扫描 所以是整个collection中的全部文档数
  20. "numYield" : 546.0, #该操作为了使其他操作完成而放弃的次数。通常来说,当他们需要访问
  21. 还没有完全读入内存中的数据时,操作将放弃。这使得在MongoDB为了
  22. 放弃操作进行数据读取的同时,还有数据在内存中的其他操作可以完成。
  23. "locks" : { #锁信息,R:全局读锁;W:全局写锁;r:特定数据库的读锁;w:特定数据库的写锁
  24. "Global" : {
  25. "acquireCount" : {
  26. "r" : NumberLong(1094) #该操作获取一个全局级锁花费的时间。
  27. }
  28. },
  29. "Database" : {
  30. "acquireCount" : {
  31. "r" : NumberLong(547)
  32. }
  33. },
  34. "Collection" : {
  35. "acquireCount" : {
  36. "r" : NumberLong(547)
  37. }
  38. }
  39. },
  40. "nreturned" : 200.0, #返回的文档数量
  41. "responseLength" : 57695.0, #返回字节长度,如果这个数字很大,考虑值返回所需字段
  42. "millis" : 264.0, #消耗的时间(毫秒)
  43. "planSummary" : "COLLSCAN, COLLSCAN", #执行概览 从这里看来 是全表扫描
  44. "execStats" : { #详细的执行计划 这里先略过 后续可以用 explain来具体分析
  45. },
  46. "ts" : ISODate("2017-08-24T02:32:49.768+0000"), #命令执行的时间
  47. "client" : "10.3.131.96", #访问的ip或者主机
  48. "allUsers" : [
  49. ],
  50. "user" : ""
  51. }

常见问题:


 
  1. 1. 如果发现 millis 值比较大,那么就需要作优化。
  2. 2. 如果docsExamined数很大,或者接近记录总数(文档数),那么可能没有用到索引查询,而是全表扫描。
  3. 3. 如果keysExamined数为0,也可能是没用索引。
  4. 4. 结合 planSummary 中的显示,上例中是 "COLLSCAN, COLLSCAN" 确认是全表扫描
  5. 5. 如果 keysExamined 值高于 nreturned 的值,说明数据库为了找到目标文档扫描了很多文档。这时可以考虑创建索引来提高效率。
  6. 6. 索引的键值选择可以根据 query 中的输出参考,上例中 filter:包含了 jzrqjglxfldm 并且按照RsId排序,所以 我们的索引
  7. 索引可以这么建: db.f10_2_8_3_jgcc.ensureindex({jzrq:1,jglxfldm:1,RsId:1}

planSummary的其他类型可选项:


 
  1. COLLSCAN #全表扫描 避免
  2. IXSCAN #索引扫描 可以改进 选用更高效的索引
  3. FETCH #根据索引去检索指定document
  4. SHARD_MERGE #将各个分片返回数据进行merge 尽可能避免跨分片查询
  5. SORT #表明在内存中进行了排序(与老版本的scanAndOrder:true一致) 排序要有index
  6. LIMIT #使用limit限制返回数 要有限制 Limit+(Fetch+ixscan)最优
  7. SKIP #使用skip进行跳过 避免不合理的skip
  8. IDHACK #针对_id进行查询 推荐,_id 默认主键,查询速度快
  9. SHARDING_FILTER #通过mongos对分片数据进行查询 SHARDING_FILTER+ixscan最优
  10. COUNT #利用db.coll.explain().count()之类进行count运算
  11. COUNTSCAN #count不使用Index进行count时的stage返回 避免 这种情况建议加索引
  12. COUNT_SCAN #count使用了Index进行count时的stage返回 推荐
  13. SUBPLA #未使用到索引的$or查询的stage返回 避免
  14. TEXT #使用全文索引进行查询时候的stage返回
  15. PROJECTION #限定返回字段时候stage的返回 选择需要的数据, 推荐PROJECTION+ixscan

 

### 如何在MongoDB中进行日志查询 #### 使用Profiler功能 MongoDB 提供了一种内置的功能——Profiler,用于捕获数据库的操作日志。此功能可以帮助开发者监控和诊断性能问题。Profiler 可以记录所有的操作日志或仅限于慢查询日志[^3]。 启用 Profiler 功能的方法如下: ```javascript db.setProfilingLevel(2, { slowms: 100 }) ``` 在此命令中,`setProfilingLevel` 的第一个参数表示级别(0 表示关闭,1 表示只记录慢查询,2 表示记录所有操作),第二个参数 `slowms` 定义了慢查询的时间阈值(单位为毫秒)。例如,以上命令将记录执行时间超过 100 毫秒的查询[^4]。 #### 查询慢日志 一旦启用了 Profiler,慢查询日志会被存储在一个名为 `system.profile` 的集合中。该集合中的文档包含了每次操作的相关信息,如查询条件、执行计划、耗时等。以下是查询慢日志的一个例子: ```javascript db.system.profile.find({ millis: { $gt: 100 } }).pretty() ``` 这条命令会返回所有执行时间大于 100 毫秒的操作详情。通过这些数据,可以进一步分析哪些查询需要优化[^5]。 #### 插入自定义日志条目 除了依赖系统的自动日志机制外,还可以手动向 MongoDB 中插入日志条目以便追踪特定事件的发生情况。这通常涉及创建一个新的集合专门用来保存应用层的日志消息,并利用 `insertOne()` 方法完成实际的数据写入工作[^2]。 例如下面这段 JavaScript 脚本展示了如何构建并存入一条包含用户活动跟踪信息的日志项: ```javascript const logEntry = { userId: 'user_123', ipAddress: '192.168.1.1', timestamp: new Date(), }; await db.logs.insertOne(logEntry); console.log('Log entry created successfully.'); ``` 这样做的好处在于能够灵活控制所要收集的信息种类及其结构形式,从而更好地服务于具体的业务需求场景下的审计与故障排查目的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值