MongoDB 最佳实践
MongoDB 最佳实践(生产级运维 + 开发 + 性能优化)完整指南,直接可用于架构设计、开发规范、数据库规划与调优。
内容:
- 架构设计最佳实践
- 数据模型 & Schema 设计
- 索引设计
- 性能优化
- 运维 & 部署最佳实践
- 安全最佳实践
- 监控最佳实践
- 开发编码最佳实践
- 常见反模式(千万不要做)
至少:
primary + secondary + arbiter(或第二个 secondary)
目的:
- 高可用
- 自动选举
- 自动故障切换
💡 不要单节点部署生产环境!
适用于:
- 单 collection > 500GB
- 单节点写入压力很大
- 需要水平扩容
分片键原则:
- 分散写入
- 不要单调递增(_id 自动生成的 ObjectId 很单调)
推荐分片键:
- hashed(_id)
- hashed(user_id)
MongoDB 默认使用 WiredTiger,支持:
- 压缩
- 文档级锁
- 更高性能
不要再使用 MMAPv1(已废弃)。
超过会报错:
BSONObj size: xxx is invalid
推荐最大 1~2MB。
✅ 什么时候用嵌套(Embed)
适合:
- 数据一对一或一对少
- 数据经常一起读取
- 例如订单 -> 商品列表
✅ 什么时候用引用(Reference)
适合:
- 一对多(非常多)
- 大量更新
- 不经常一起读取
推荐:
snake_case(推荐)
camelCase(也可以)
⚠️ 不要使用中文字段名。
深度 > 5 层 会导致查询性能变差。
- where 查询字段
- sort 排序字段
- join 字段($lookup)
- 唯一字段(unique)
如复合索引:
{ a: 1, b: 1, c: 1 }
有效索引字段是:
a
a, b
a, b, c
不能直接用 b, c。
每个 index 都会:
- 占用内存
- 降低写入性能
db.collection.find({...}).explain("executionStats")
出现 COLLSCAN 必须加索引。
❌ 错误:
db.users.find({ name: /abc/ })
✅ 正确:
db.users.find({ name: /^abc/ })
❌:
id in [1,2,3,4...50000]
会导致 huge COLLSCAN。
比 skip 快数十倍。
db.collection.aggregate([...], { allowDiskUse: true })
只要需要字段:
{ name: 1, age: 1 }
理由:
- WiredTiger 需要大量随机 I/O
- SSD 显著提升写入性能
设置:
vm.swappiness = 1
查看:
rs.printReplicationInfo()
避免:
- 太多小集合
- 每个都有索引 -> 内存爆炸
security:
authorization: enabled
避免用户权限过高。
创建最小权限用户:
db.createUser({
user: "app",
pwd: "xxx",
roles: [{ role: "readWrite", db: "mydb" }]
})
开启证书加密传输。
必监控指标:
WiredTiger:
- cache usage
- eviction
- dirty bytes
Replication:
- replication lag(必须 < 10 秒)
- oplog time window
Performance:
- opcounters
- slow queries
- queue length
- I/O 读写
推荐使用:
- Prometheus + Grafana
- Percona Monitoring (PMM)
✅ 使用连接池(pool)
例如:
updateOne(upsert=True)
会触发:
- document move
- rewrite entire doc
成本高!
批量性能比循环 insert 快 10x+。
- ❌ 大量使用 $where(JS 执行,极慢)
- ❌ 使用 skip 进行深度分页(性能噩梦)
- ❌ 在字段上使用正则前置通配符 .*abc
- ❌ 文档无限深度嵌套
- ❌ 同一集合创建几十个索引
- ❌ 垃圾分片键导致热点问题
- ❌ 多字段常改 -> 嵌套太深造成整文档重写