db.currentOp() 可定位事务卡点:secs_running高且waitingForLock为false说明执行慢,true则表明锁等待,低值但延迟高需查驱动或网络;system.profile需按lsid+txnNumber聚合分析;explain("executionStats")才能准确定位索引与扫描问题。

用 db.currentOp() 看清事务卡在哪一步
事务慢,往往不是“事务本身”慢,而是里面某条操作在拖后腿。直接运行 db.currentOp({ "secs_running": { "$gt": 5 }, "lsid": { "$exists": true } }),能筛出运行超 5 秒且属于某个会话(即事务)的操作。
重点关注三个字段:
-
secs_running高 +waitingForLock: false→ 真实执行耗时高,比如聚合没索引、$lookup没走上索引、或文档太大导致序列化/反序列化慢 -
waitingForLock: true→ 当前事务在等锁,说明有其他长事务或写密集操作占着资源;查secs_running最高的那个 op,它大概率是锁源头 -
secs_running低但客户端感知延迟高 → 不是数据库内问题,可能是驱动批量提交策略(如默认 100ms 批量 flush)、网络 RTT 高、或事务外的连接建立/认证开销
查 system.profile 时必须按 lsid + txnNumber 聚合
Profiler 默认不记录 commitTransaction 或 abortTransaction,只记录事务内部的真实操作(find、update、insert 等),而且不会打上 “transaction” 标签。光看单条日志容易误判——你以为是一次慢查询,其实是事务里第 3 条语句。
正确做法是:db.system.profile.find({ "lsid": { "$exists": true }, "txnNumber": { "$exists": true } }).sort({ "ts": 1 }),再人工或脚本按 lsid 和 txnNumber 分组,还原完整执行序列。
关键指标要交叉看:
-
nScannedObjects远大于nReturned→ 对应的find或update很可能没走索引,触发 collection scan -
keysExamined高但nScannedObjects低 → 索引扫描范围大(比如{ ts: 1, status: 1 }上查ts > X但没加status条件),实际命中文档少 -
docsExamined明显高于预期更新数 → update/delete 缺少有效筛选条件,或索引失效(比如用了$regex前缀通配)
别信 millis 单一数值,得看 explain("executionStats") 复现
Profiler 里的 millis 是命令执行时间,但它不包含网络传输、驱动解析、事务协调开销。尤其对小文档高频事务,millis 可能只有几毫秒,但端到端延迟却上百毫秒——这时候瓶颈在连接池争用或 WiredTiger 日志刷盘压力。
真正定位执行层瓶颈,得回到原始语句,手动加 .explain("executionStats"):
- 确认
winningPlan.stage是IXSCAN而非COLLSCAN - 检查
executionStats.totalDocsExamined是否与业务逻辑匹配(比如只该改 1 条却扫了 10 万条) - 留意
executionStats.nChunkSkips(分片场景下跨 chunk 跳过成本高)和executionStats.replanReason(计划被强制重选,说明统计信息过期)
开启 Profiler 的阈值和范围必须精准控制
在生产环境开 Profiler,不能无差别设 slowms: 100 就完事。事务内多条语句叠加,哪怕每条都 10ms)又会导致 system.profile 写入风暴,反而拖慢 WiredTiger。
推荐组合策略:
- 先临时设为
db.setProfilingLevel(1, { slowms: 50, sampleRate: 0.1 }),用低采样率抓典型 - 针对已知慢事务的
lsid,用db.setProfilingLevel(2)开全量(仅限排查窗口期,事后立刻关) - 绝对不要在分片集群的 mongos 上开 Profiler —— 它只记录 mongos 层路由行为,看不到真正执行的 shard 上发生了什么
最易被忽略的一点:事务中若含 readConcern: "snapshot",WiredTiger 需维护更长的旧版本数据链,%dirty 会上升,IO 压力隐性放大——这种影响不会直接出现在 Profiler 的 millis 里,得结合 mongostat 的 faults/s 和 WiredTiger.cache.* 指标交叉验证。



















