MongoDB性能优化 #
一、性能优化概述 #
1.1 优化方向 #
| 方向 | 说明 |
|---|---|
| 查询优化 | 优化查询语句和索引 |
| 索引优化 | 设计合适的索引策略 |
| 配置优化 | 调整MongoDB配置 |
| 架构优化 | 优化数据库架构 |
| 硬件优化 | 升级硬件资源 |
1.2 性能指标 #
| 指标 | 说明 |
|---|---|
| QPS | 每秒查询数 |
| 延迟 | 查询响应时间 |
| 吞吐量 | 数据处理量 |
| 资源使用 | CPU、内存、磁盘 |
二、查询优化 #
2.1 使用explain分析 #
javascript
// 基本分析
db.users.find({ name: "John" }).explain()
// 详细分析
db.users.find({ name: "John" }).explain("executionStats")
// 关键指标
{
executionStats: {
totalDocsExamined: 1000, // 扫描文档数
totalKeysExamined: 1000, // 扫描索引键数
nReturned: 10, // 返回文档数
executionTimeMillis: 5 // 执行时间
}
}
2.2 优化查询语句 #
javascript
// 不推荐:全表扫描
db.users.find({ name: /John/ })
// 推荐:使用索引
db.users.find({ name: /^John/ })
// 不推荐:使用$where
db.users.find({ $where: "this.age > 20" })
// 推荐:使用操作符
db.users.find({ age: { $gt: 20 } })
// 不推荐:返回所有字段
db.users.find({ name: "John" })
// 推荐:只返回需要的字段
db.users.find({ name: "John" }, { name: 1, email: 1 })
2.3 使用投影 #
javascript
// 减少返回字段
db.users.find(
{ status: "active" },
{ name: 1, email: 1, _id: 0 }
)
2.4 使用limit #
javascript
// 限制返回数量
db.users.find().limit(100)
// 分页查询
db.users.find().skip(100).limit(100)
2.5 避免慢查询 #
javascript
// 开启慢查询日志
db.setProfilingLevel(1, 100) // 记录超过100ms的查询
// 查看慢查询
db.system.profile.find().sort({ ts: -1 }).limit(10)
// 分析慢查询
db.system.profile.aggregate([
{ $group: { _id: "$ns", count: { $sum: 1 }, avgTime: { $avg: "$millis" } } },
{ $sort: { avgTime: -1 } }
])
三、索引优化 #
3.1 创建合适的索引 #
javascript
// 单字段索引
db.users.createIndex({ email: 1 })
// 复合索引
db.users.createIndex({ status: 1, createdAt: -1 })
// 多键索引
db.users.createIndex({ tags: 1 })
// 文本索引
db.articles.createIndex({ content: "text" })
3.2 索引设计原则 #
text
索引设计原则
1. 选择性高的字段
- 区分度高的字段
- 避免在低基数字段创建索引
2. 查询模式匹配
- 根据查询模式设计索引
- 复合索引遵循最左前缀
3. 排序优化
- 排序字段考虑索引
- 复合索引支持排序
4. 覆盖查询
- 查询字段都在索引中
- 避免回表查询
3.3 覆盖查询 #
javascript
// 创建复合索引
db.users.createIndex({ name: 1, email: 1 })
// 覆盖查询(只查询索引字段)
db.users.find(
{ name: "John" },
{ name: 1, email: 1, _id: 0 }
)
// 验证是否覆盖查询
db.users.find({ name: "John" }, { name: 1, email: 1, _id: 0 }).explain()
// 查看executionStats.totalDocsExamined是否为0
3.4 索引监控 #
javascript
// 查看索引使用情况
db.users.aggregate([
{ $indexStats: {} }
])
// 查找未使用的索引
db.users.aggregate([
{ $indexStats: {} },
{ $match: { "accesses.ops": 0 } }
])
// 查看索引大小
db.users.stats().indexSizes
3.5 删除冗余索引 #
javascript
// 查看冗余索引
// 如果有索引 { a: 1, b: 1 },则索引 { a: 1 } 是冗余的
// 删除冗余索引
db.users.dropIndex("a_1")
四、配置优化 #
4.1 内存配置 #
yaml
# mongod.conf
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 4 # 缓存大小(建议50%系统内存)
4.2 连接配置 #
yaml
# mongod.conf
net:
maxIncomingConnections: 65536
4.3 日志配置 #
yaml
# mongod.conf
systemLog:
verbosity: 0
quiet: false
logRotate: rename
4.4 写关注配置 #
javascript
// 设置默认写关注
db.adminCommand({
setDefaultRWConcern: 1,
defaultWriteConcern: { w: "majority" }
})
五、架构优化 #
5.1 分片优化 #
javascript
// 选择合适的分片键
sh.shardCollection("mydb.users", { userId: "hashed" })
// 预分割Chunk
sh.splitAt("mydb.users", { userId: 1000 })
sh.splitAt("mydb.users", { userId: 2000 })
5.2 复制集优化 #
javascript
// 读写分离
db.getMongo().setReadPref("secondaryPreferred")
// 使用标签
db.users.find().readPref("secondary", [{ dc: "east" }])
5.3 集合设计优化 #
javascript
// 嵌套文档 vs 引用文档
// 嵌套文档:适合一对一、一对少
{
user: {
name: "John",
address: { city: "Beijing" }
}
}
// 引用文档:适合一对多、多对多
{
user: { _id: 1, name: "John" },
orders: [{ orderId: 1 }, { orderId: 2 }]
}
六、硬件优化 #
6.1 存储优化 #
text
存储建议
1. 使用SSD
- 随机IO性能更好
- 降低延迟
2. RAID配置
- RAID 10:性能和冗余
- 避免RAID 5/6
3. 文件系统
- XFS:推荐
- ext4:兼容性好
6.2 内存优化 #
text
内存建议
1. 足够的内存
- 工作集应该能放入内存
- WiredTiger缓存50%系统内存
2. 避免交换
- 关闭swap或限制使用
6.3 CPU优化 #
text
CPU建议
1. 多核CPU
- MongoDB多线程
- 更多核心更好
2. 高主频
- 单线程操作更快
七、监控与诊断 #
7.1 服务器状态 #
javascript
// 查看服务器状态
db.serverStatus()
// 关键指标
{
connections: { current: 100, available: 50000 },
network: { bytesIn: 1000000, bytesOut: 2000000 },
opcounters: { query: 1000, insert: 500, update: 200 },
memory: { resident: 1024, virtual: 2048 }
}
7.2 数据库统计 #
javascript
// 查看数据库统计
db.stats()
// 查看集合统计
db.users.stats()
7.3 当前操作 #
javascript
// 查看当前操作
db.currentOp()
// 查看长时间运行的操作
db.currentOp({ "secs_running": { $gt: 5 } })
// 终止操作
db.killOp(opId)
7.4 性能监控工具 #
text
监控工具
1. MongoDB Atlas
- 云监控
- 性能洞察
2. MongoDB Compass
- 可视化监控
- 查询分析
3. Prometheus + Grafana
- 自定义监控
- 告警配置
4. MongoDB Ops Manager
- 企业级监控
- 自动化管理
八、常见性能问题 #
8.1 查询慢 #
javascript
// 分析原因
db.users.find({ name: "John" }).explain("executionStats")
// 解决方案
// 1. 创建索引
db.users.createIndex({ name: 1 })
// 2. 使用覆盖查询
db.users.find({ name: "John" }, { name: 1, email: 1, _id: 0 })
// 3. 限制返回数量
db.users.find({ name: "John" }).limit(100)
8.2 写入慢 #
javascript
// 分析原因
db.currentOp({ "op": "write" })
// 解决方案
// 1. 批量写入
db.users.insertMany([...])
// 2. 降低写关注
db.users.insertOne({...}, { writeConcern: { w: 1 } })
// 3. 无序写入
db.users.insertMany([...], { ordered: false })
8.3 内存不足 #
javascript
// 分析原因
db.serverStatus().memory
// 解决方案
// 1. 增加内存
// 2. 优化查询减少内存使用
// 3. 调整缓存大小
九、最佳实践 #
9.1 查询优化建议 #
text
1. 使用索引
2. 使用投影
3. 使用limit
4. 避免全表扫描
5. 使用覆盖查询
9.2 索引优化建议 #
text
1. 选择性高的字段
2. 复合索引设计
3. 删除冗余索引
4. 定期重建索引
5. 监控索引使用
9.3 配置优化建议 #
text
1. 合理配置内存
2. 调整连接数
3. 优化日志级别
4. 使用合适的写关注
十、总结 #
性能优化速查表:
| 优化方向 | 方法 |
|---|---|
| 查询优化 | 使用索引、投影、limit |
| 索引优化 | 创建合适索引、删除冗余索引 |
| 配置优化 | 内存、连接、日志配置 |
| 架构优化 | 分片、复制集、集合设计 |
| 硬件优化 | SSD、内存、CPU |
常用诊断命令:
| 命令 | 说明 |
|---|---|
| db.serverStatus() | 服务器状态 |
| db.stats() | 数据库统计 |
| db.currentOp() | 当前操作 |
| explain() | 查询分析 |
恭喜你完成了MongoDB学习之旅!
最后更新:2026-03-27