1. 为什么需要优化?
MongoDB
虽然灵活,但如果不加优化,可能出现:
查询性能低(扫描全表)
分片热点(某一分片压力过大)
内存占用高(缓存无效)
写入延迟大(锁竞争)
优化的核心目标是:减少扫描量,减少锁竞争,充分利用索引与缓存。
2. 索引优化(Index Optimization)
MongoDB 查询性能的关键就是索引。
2.1 索引类型
类型 | 作用 | 示例 |
---|---|---|
单字段索引 | 针对单个字段 | db.users.createIndex({ age: 1 }) |
复合索引 | 多个字段组合 | db.users.createIndex({ name: 1, age: -1 }) |
唯一索引 | 防止重复值 | db.users.createIndex({ email: 1 }, { unique: true }) |
文本索引 | 搜索文本 | db.articles.createIndex({ content: “text” }) |
地理索引 | 地理位置查询 | db.locations.createIndex({ loc: “2dsphere” }) |
2.2 索引命中原则
查询条件中用到的字段要有索引
复合索引遵循最左前缀原则
例如:
1
db.users.createIndex({ name: 1, age: 1 })
这个索引可用于:
{ name: "Tom" }
{ name: "Tom", age: 25 }
但不能用于:{ age: 25 }
(会全表扫描)
避免过多索引(写入成本高,内存占用大)
定期清理无用索引:
1
db.users.dropIndex("name_1")
2.3 查看查询是否使用索引
1 | db.users.find({ age: { $gt: 25 } }).explain("executionStats") |
如果输出中 "stage"
是 "COLLSCAN"
→ 全表扫描,需要优化。
如果是 "IXSCAN"
→ 命中索引。
3. 查询优化(Query Optimization)
3.1 只取需要的字段
1 | db.users.find({}, { name: 1, age: 1, _id: 0 }) |
减少网络传输与内存占用。
3.2 避免 $where、正则前缀模糊
1 | // 慢(无法利用索引) |
3.3 提前过滤 $match
聚合时 $match
放前面,减少后续数据量:
1 | db.orders.aggregate([ |
3.4 批量写入
1 | db.collection.insertMany([...], { ordered: false }) |
并行插入数据,减少锁竞争。
4. 分片优化(Sharding Optimization)
4.1 选择合适的分片键
高基数(
cardinality
)字段,例如 userId
(避免低基数字段导致数据集中在少数分片)避免时间戳作为唯一分片键(会产生热点写入)
考虑复合分片键,例如
{ region: 1, userId: 1 }
4.2 预分片
大规模导入数据前,先预分片:
1 |
|
4.3 均衡分布
定期检查分片均衡:
1 | sh.status() |
如果不均衡,可手动触发:
1 | sh.startBalancer() |
5. 聚合优化(Aggregation Optimization)
5.1 $match 前置
将过滤条件尽量放在管道前端,减少后续处理数据量。
5.2 $project 提前裁剪字段
1 | db.orders.aggregate([ |
5.3 避免 $lookup 过多
跨集合关联查询代价大,可以考虑:
数据冗余(反范式设计)
预计算结果存储到新集合
6. 实测优化建议
我做过一次 1000
万条订单数据的优化对比:
优化前(无索引) | 优化后(加索引 + $match 前置) |
---|---|
查询耗时:12.4s | 查询耗时:0.8s |
CPU 占用:95% | CPU 占用:25% |
内存占用:8GB | 内存占用:3GB |
7. 运维与监控
7.1 常用工具
mongostat
→ 实时查看QPS
、锁、缓存命中率mongotop
→ 查看集合读写耗时db.serverStatus()
→ 查看实例状态
7.2 性能监控平台
MongoDB Atlas(官方云监控)
Prometheus + Grafana(开源可视化)
8. 总结
MongoDB 性能优化的核心公式:
1 | 高效索引 + 合理分片键 + 精简查询字段 + 聚合前置过滤 |
建议开发时就养成:
先设计索引再写查询
定期
explain()
检查查询计划高并发场景下,优先副本集 + 分片结合
聚合复杂计算时,考虑预计算表