MongoDBNotes

第 25 章:性能调优

zjc 于 2026-01-25 发布

这是《MongoDB 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 性能调优目标是满足业务 SLA,而不是追求单条查询极限。MongoDB 调优通常从查询和索引开始,再处理 Schema、cache、磁盘、复制和分片。

25.1 调优流程

define latency targets
  -> collect baseline
  -> find slow operations
  -> explain query
  -> fix indexes / schema
  -> tune workload
  -> test under concurrency
  -> monitor result

目标示例:

指标 目标
订单读 P99 < 20 ms
订单写 P99 < 50 ms
副本延迟 < 1 s
复制延迟峰值 < 5 s
慢查询 < 0.1%

25.2 查询优化

优先做:

  1. 高频查询加复合索引;
  2. 排序字段进索引;
  3. 投影减少返回;
  4. 游标分页;
  5. $match 前移;
  6. 控制 $in 大小;
  7. 避免非前缀正则;
  8. 高频搜索使用专用索引。

验证:

db.orders.find({
  user_id: "u_1001",
  status: "PAID"
}).explain("executionStats")

目标:

IXSCAN
nReturned ≈ keysExamined
no SORT

25.3 写入优化

优化点:

  1. 减少无效索引;
  2. 批量写入控制批次;
  3. 拆小事务;
  4. 避免热点文档;
  5. 避免超大数组更新;
  6. 延迟 Secondary 负载;
  7. 控制文档增长;
  8. 大字段拆分;
  9. 使用合适的写关注。

批量写入:

db.orders.bulkWrite([
  { insertOne: { document: { _id: "o_1", status: "CREATED" } } },
  { insertOne: { document: { _id: "o_2", status: "CREATED" } } }
], { ordered: false })

25.4 Cache 调优

查看:

db.serverStatus().wiredTiger.cache

处理:

信号 优化
pages read 高 增内存、缩工作集
dirty pages 高 降写入、检查磁盘
evict waiting 降低并发或扩 cache
checkpoint 慢 减少脏页和索引

更有效的方向通常是减少工作集:拆冷数据、投影、减少索引和控制文档大小。

25.5 磁盘与文件系统

建议:

  1. 数据盘使用 SSD 或 NVMe;
  2. 监控 util、latency、IOPS;
  3. 预留空间;
  4. journal 与数据目录按官方建议部署;
  5. 避免与重 IO 服务混部;
  6. 定期验证快照性能;
  7. 关注磁盘队列和 iowait。

25.6 副本集性能

关注:

  1. Primary 写入延迟;
  2. Secondary 复制延迟;
  3. oplog 窗口;
  4. Secondary 读负载;
  5. 索引构建;
  6. 网络带宽;
  7. 心跳和选举健康。

优化:

  1. Secondary 只承担可延迟读;
  2. 报表使用 Hidden Secondary;
  3. 避免同时重建所有节点索引;
  4. 大事务拆小;
  5. 跨机房部署评估同步延迟。

25.7 分片性能

优化:

  1. 高频查询带分片键;
  2. 避免广播查询;
  3. 分片键分布均匀;
  4. 控制 jumbo chunk;
  5. balancer 低峰运行;
  6. mongos 足够实例;
  7. 减少跨 shard 事务;
  8. 监控每 shard 负载。

25.8 应用侧优化

  1. 使用连接池;
  2. 控制连接数;
  3. 设置查询超时;
  4. 使用读写关注策略;
  5. 请求携带 trace ID;
  6. 幂等重试;
  7. 避免每请求全量查询;
  8. 本地缓存热点数据;
  9. 批处理错峰;
  10. 熔断非核心查询。

25.9 压测

压测场景:

  1. 读写混合;
  2. 热点用户;
  3. 聚合报表;
  4. 大批量导入;
  5. Secondary 读;
  6. 分片迁移;
  7. Primary 切换;
  8. 索引上线;
  9. 长稳测试。

记录:

throughput
p95 / p99 latency
error rate
cache metrics
disk metrics
replication lag
application result

25.10 反模式

反模式 后果
只看平均延迟 掩盖长尾
索引越多越好 写入变慢
事务包住外部调用 长事务
Secondary 读解决一切 读旧数据
分片解决慢查询 广播更慢
盲目调 cache 抢占系统内存
生产直接建大索引 影响线上

本章小结

MongoDB 性能优化通常先修查询、索引和 Schema,再治理工作集、磁盘和复制延迟。写入端关注热点和索引成本,分片端关注路由和均衡。所有优化都必须通过并发压测和上线后监控验证。

思考题

  1. 为什么先优化查询再扩容?
  2. 工作集大于内存有什么表现?
  3. 索引过多的写入代价是什么?
  4. 分片为什么可能让慢查询更慢?
  5. 压测为什么必须包含长稳阶段?