Appearance
性能优化
查询优化
分析查询性能
explain
javascript
db.users.find({ name: '张三' }).explain('executionStats')关键指标
| 指标 | 说明 |
|---|---|
| totalDocsExamined | 扫描文档数 |
| totalKeysExamined | 扫描索引键数 |
| nReturned | 返回文档数 |
| executionTimeMillis | 执行时间 |
优化目标
totalDocsExamined ≈ nReturned
totalKeysExamined ≈ nReturned查询优化建议
1. 使用索引
javascript
db.users.find({ name: '张三' })
db.users.createIndex({ name: 1 })2. 限制返回字段
javascript
db.users.find({}, { name: 1, email: 1, _id: 0 })3. 使用 limit
javascript
db.users.find().limit(100)4. 避免使用 $where
javascript
db.users.find({ $where: 'this.age > 20' })
db.users.find({ age: { $gt: 20 } })5. 批量操作
javascript
for (let i = 0; i < 1000; i++) {
db.users.insertOne({ name: `user_${i}` })
}
let docs = []
for (let i = 0; i < 1000; i++) {
docs.push({ name: `user_${i}` })
}
db.users.insertMany(docs)慢查询分析
开启慢查询日志
javascript
db.setProfilingLevel(1, { slowms: 100 })查看慢查询
javascript
db.system.profile.find().sort({ ts: -1 }).limit(10)分析级别
| 级别 | 说明 |
|---|---|
| 0 | 关闭 |
| 1 | 只记录慢查询 |
| 2 | 记录所有操作 |
javascript
db.setProfilingLevel(0)
db.setProfilingLevel(1, { slowms: 50 })
db.setProfilingLevel(2)索引优化
索引设计原则
1. ESR 原则
Equality → Sort → Range
javascript
db.users.find({ city: '北京' }).sort({ age: -1 }).skip(0).limit(10)
db.users.createIndex({ city: 1, age: -1 })2. 覆盖索引
javascript
db.users.createIndex({ name: 1, email: 1 })
db.users.find(
{ name: '张三' },
{ _id: 0, name: 1, email: 1 }
)3. 选择性高的字段
javascript
db.users.aggregate([
{
$group: {
_id: '$status',
count: { $sum: 1 }
}
}
])索引监控
查看索引使用情况
javascript
db.users.aggregate([{ $indexStats: {} }])查看未使用的索引
javascript
db.users.aggregate([
{ $indexStats: {} },
{ $match: { 'accesses.ops': 0 } }
])删除无用索引
javascript
db.users.dropIndex('unused_index_name')写入优化
批量写入
javascript
db.users.insertMany([
{ name: '张三' },
{ name: '李四' },
{ name: '王五' }
])有序 vs 无序
javascript
db.users.insertMany([...], { ordered: false })写关注调整
javascript
db.users.insertOne(
{ name: '张三' },
{ writeConcern: { w: 1 } }
)使用 bulkWrite
javascript
db.users.bulkWrite([
{ insertOne: { document: { name: '用户A' } } },
{ updateOne: { filter: { name: '张三' }, update: { $set: { age: 25 } } } },
{ deleteOne: { filter: { name: '李四' } } }
], { ordered: false })内存优化
WiredTiger 缓存
yaml
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 4查看内存使用
javascript
db.serverStatus().wiredTiger.cache缓存指标
| 指标 | 说明 |
|---|---|
| bytes currently in the cache | 缓存使用量 |
| maximum bytes configured | 最大缓存配置 |
| pages read into cache | 读入缓存的页数 |
| pages written from cache | 从缓存写出的页数 |
内存优化建议
- 设置合适的缓存大小(通常为内存的 50%)
- 避免大文档
- 使用投影减少返回数据
- 合理使用索引
连接池优化
连接池配置
javascript
const { MongoClient } = require('mongodb')
const client = new MongoClient(uri, {
maxPoolSize: 100,
minPoolSize: 10,
maxIdleTimeMS: 30000,
waitQueueTimeoutMS: 5000
})连接池参数
| 参数 | 说明 |
|---|---|
| maxPoolSize | 最大连接数 |
| minPoolSize | 最小连接数 |
| maxIdleTimeMS | 空闲超时时间 |
| waitQueueTimeoutMS | 等待超时时间 |
查看连接状态
javascript
db.serverStatus().connections存储优化
文档大小优化
避免大文档
javascript
db.articles.insertOne({
title: '文章标题',
content: '很长的内容...'
})
db.articles.insertOne({
title: '文章标题',
content_id: ObjectId('...')
})字段名缩短
javascript
db.users.insertOne({
username: '张三',
emailAddress: 'test@example.com'
})
db.users.insertOne({
u: '张三',
e: 'test@example.com'
})压缩
yaml
storage:
wiredTiger:
collectionConfig:
blockCompressor: snappy
indexConfig:
prefixCompression: true压缩算法
| 算法 | 说明 |
|---|---|
| none | 不压缩 |
| snappy | 快速压缩(默认) |
| zlib | 高压缩比 |
| zstd | 高性能压缩 |
分片优化
分片键选择
选择原则
- 高基数(Cardinality)
- 低频率(Frequency)
- 单调性变化
分片键类型
| 类型 | 说明 |
|---|---|
| 范围分片 | 按范围分布 |
| 哈希分片 | 均匀分布 |
javascript
sh.shardCollection('mydb.users', { _id: 'hashed' })
sh.shardCollection('mydb.orders', { user_id: 1 })分片监控
javascript
sh.status()
db.users.getShardDistribution()均衡器
javascript
sh.stopBalancer()
sh.startBalancer()
sh.setBalancerState(false)监控工具
serverStatus
javascript
db.serverStatus()
db.serverStatus().connections
db.serverStatus().opcounters
db.serverStatus().memorydbStats
javascript
db.stats()
db.stats(1024 * 1024)collectionStats
javascript
db.users.stats()
db.users.stats({ scale: 1024 })currentOp
javascript
db.currentOp()
db.currentOp({ 'active': true, 'secs_running': { $gt: 5 } })终止操作
javascript
db.killOp(opId)性能分析工具
MongoDB Compass
图形化界面工具,支持:
- 查询构建
- 索引分析
- 性能监控
mongostat
bash
mongostat --host localhost --port 27017
mongostat 5mongotop
bash
mongotop --host localhost --port 27017
mongotop 5Atlas Performance Advisor
MongoDB Atlas 云服务提供的性能建议工具。
性能优化清单
查询优化
- [ ] 使用 explain 分析慢查询
- [ ] 创建合适的索引
- [ ] 使用覆盖索引
- [ ] 限制返回字段
- [ ] 使用 limit 限制结果
索引优化
- [ ] 遵循 ESR 原则
- [ ] 删除未使用的索引
- [ ] 使用复合索引
- [ ] 考虑部分索引
写入优化
- [ ] 使用批量写入
- [ ] 调整写关注级别
- [ ] 使用无序写入
内存优化
- [ ] 设置合适的缓存大小
- [ ] 监控内存使用
- [ ] 优化文档大小
连接优化
- [ ] 配置连接池
- [ ] 监控连接数
- [ ] 设置超时时间
常见性能问题
1. 全表扫描
javascript
db.users.find({ name: '张三' }).explain()
db.users.createIndex({ name: 1 })2. 内存排序
javascript
db.users.find().sort({ age: -1 }).explain()
db.users.createIndex({ age: -1 })3. 连接数过多
javascript
db.serverStatus().connections
db.adminCommand({ setParameter: 1, maxIncomingConnections: 1000 })4. 写入性能低
- 使用批量写入
- 调整写关注级别
- 检查索引数量
5. 查询超时
javascript
db.users.find({ name: '张三' }).maxTimeMS(5000)