事务本身不拖慢mongodb,真正卡住的是锁竞争和未命中索引的读写操作;wiredtiger下全表扫描会升级为集合级争用,导致锁排队、millis飙升、totaldocsexamined远超nreturned。

事务本身不直接拖慢 MongoDB,真正卡住的是锁竞争 + 未命中索引的读写操作。 在 WiredTiger 引擎下,事务默认使用文档级锁,但一旦查询或更新触发全集合扫描(COLLSCAN),就会升级为集合级争用;更糟的是,多个事务反复访问同一片数据区域时,会形成锁排队,millis 指标飙升、totalDocsExamined 远大于 nReturned 就是典型信号。
为什么事务里一查就慢:explain("executionStats") 必须看
事务内部的查询如果没走索引,WiredTiger 仍要扫描大量文档——而事务生命周期内这些文档会被加读锁或写锁,阻塞其他并发事务。这不是“事务慢”,是“没索引的查询在事务里被放大了影响”。
- 执行
db.collection.explain("executionStats").find(...),重点盯executionStats.totalDocsExamined和nReturned的比值;超过 10:1 就危险 - 检查
executionStats.executionStages.stage是否为COLLSCAN;若是,说明当前查询条件完全没用上索引 - 事务中避免使用
$where、正则无前缀(如/abc$/)、$text等无法高效利用 B-tree 索引的操作 - 复合索引字段顺序必须匹配查询谓词顺序,例如
createIndex({a:1, b:-1, c:1})支持{a:1, b:2},但不支持{b:2, c:3}
事务锁冲突高发场景:高频更新同一文档或范围
哪怕有索引,如果多个事务频繁修改同一个文档(比如计数器、状态字段),或批量更新重叠的时间范围(如 createdAt: {$gte: ..., $lt: ...}),WiredTiger 的文档级锁也会退化为“逻辑热点”,表现为 wt_txn_update_conflict 计数持续上升、事务重试率变高。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 用
db.serverStatus().metrics.operation.write.conflicts查看写冲突总数;生产环境每秒 > 5 次就需干预 - 避免在事务中做“读-改-写”循环(如先 find 再 update),改用
findOneAndUpdate原子操作 - 对统计类字段(如
viewCount),考虑用异步队列+定期聚合替代实时事务更新 - 分片集群下,确保事务只涉及单一分片(即查询含分片键),否则跨分片事务会强制升级为全局锁协调,延迟陡增
连接池 + 事务超时配置不当会雪上加霜
事务未及时提交或回滚,会一直占着连接和锁资源。而默认驱动连接池往往不够大,导致新请求排队等待连接,进一步加剧锁等待链。
- Node.js 驱动示例:设置
maxPoolSize: 50(非默认 100)+minPoolSize: 10,并启用maxIdleTimeMS: 60000 - 所有事务必须显式设
maxTimeMS,例如session.startTransaction({ maxTimeMS: 5000 }),防止长事务霸占资源 - 避免在事务中调用外部 HTTP 请求或长时间计算;MongoDB 事务不支持挂起,超时即中断且可能留下部分写入
- 监控
currentQueue和available连接数(来自db.serverStatus().connections),若currentQueue > 10且持续存在,说明连接已成瓶颈
最容易被忽略的一点:事务性能问题往往不是孤立出现的,而是索引缺失、连接池过小、查询设计粗糙三者叠加的结果。单独调大连接池或缩短事务超时,都治标不治本;必须从 explain 报告出发,定位第一个 COLLSCAN 或高 docsExamined 的操作,把它切掉——这才是真正掐住性能下滑咽喉的位置。










