乐闻世界logo
搜索文章和话题

Mongoose 性能优化有哪些最佳实践?

2月22日 20:12

Mongoose 性能优化是开发高效应用的关键。通过合理的配置和最佳实践,可以显著提升查询速度和整体性能。

连接优化

连接池配置

javascript
mongoose.connect('mongodb://localhost:27017/mydb', { maxPoolSize: 100, // 最大连接数 minPoolSize: 10, // 最小连接数 socketTimeoutMS: 45000, // 套接字超时 serverSelectionTimeoutMS: 5000, // 服务器选择超时 connectTimeoutMS: 10000 // 连接超时 });

连接重用

javascript
// 在应用启动时建立连接 mongoose.connect('mongodb://localhost:27017/mydb'); // 不要频繁关闭和重新连接 // 避免在每次请求时都创建新连接

索引优化

创建索引

javascript
const userSchema = new Schema({ email: { type: String, index: true, // 单字段索引 unique: true }, name: { type: String, index: true }, age: Number, status: String }); // 复合索引 userSchema.index({ status: 1, age: -1 }); // 文本索引 userSchema.index({ name: 'text', bio: 'text' }); // 地理空间索引 userSchema.index({ location: '2dsphere' });

索引策略

  1. 为常用查询字段创建索引
  2. 使用复合索引优化多字段查询
  3. 避免过多索引影响写入性能
  4. 定期分析查询性能,优化索引
javascript
// 分析查询计划 const query = User.find({ email: 'john@example.com' }); const explanation = await query.explain('executionStats'); console.log(explanation.executionStats);

查询优化

使用 lean()

javascript
// 返回普通 JavaScript 对象,性能更好 const users = await User.find().lean(); // 只读查询使用 lean() const users = await User.find({ status: 'active' }).lean();

选择性查询

javascript
// 只查询需要的字段 const users = await User.find() .select('name email age') .lean(); // 排除大字段 const users = await User.find() .select('-largeField -anotherLargeField');

限制结果数量

javascript
// 使用 limit 限制返回数量 const users = await User.find() .limit(100); // 实现分页 const page = 1; const pageSize = 20; const users = await User.find() .skip((page - 1) * pageSize) .limit(pageSize);

使用投影

javascript
// 投影减少数据传输 const users = await User.find( { status: 'active' }, { name: 1, email: 1, _id: 0 } );

批量操作

批量插入

javascript
// 使用 insertMany 代替多次 insertOne const users = await User.insertMany([ { name: 'John', email: 'john@example.com' }, { name: 'Jane', email: 'jane@example.com' }, // ... 更多用户 ]);

批量更新

javascript
// 使用 updateMany 代替多次 updateOne await User.updateMany( { status: 'pending' }, { status: 'active' } );

批量删除

javascript
// 使用 deleteMany 代替多次 deleteOne await User.deleteMany({ status: 'deleted' });

缓存策略

查询缓存

javascript
const userSchema = new Schema({ name: String, email: String }, { query: { cache: true } }); // 启用缓存 const users = await User.find().cache(); // 设置缓存时间 const users = await User.find().cache(60); // 60秒

应用层缓存

javascript
const NodeCache = require('node-cache'); const cache = new NodeCache({ stdTTL: 600 }); // 10分钟缓存 async function getUserById(userId) { const cacheKey = `user:${userId}`; let user = cache.get(cacheKey); if (!user) { user = await User.findById(userId).lean(); if (user) { cache.set(cacheKey, user); } } return user; }

数据模型优化

嵌入 vs 引用

javascript
// 嵌入适合一对一或一对多,子文档较小 const userSchema = new Schema({ name: String, profile: { bio: String, avatar: String } }); // 引用适合一对多或多对多,子文档较大 const postSchema = new Schema({ title: String, author: { type: Schema.Types.ObjectId, ref: 'User' } });

避免过深嵌套

javascript
// 避免过深的嵌套结构 // 不推荐 const badSchema = new Schema({ level1: { level2: { level3: { level4: { data: String } } } } }); // 推荐:扁平化结构 const goodSchema = new Schema({ level1: String, level2: String, level3: String, level4: String });

监控和调优

查询性能监控

javascript
// 启用调试模式 mongoose.set('debug', true); // 自定义调试函数 mongoose.set('debug', (collectionName, method, query, doc) => { console.log(`${collectionName}.${method}`, JSON.stringify(query)); });

慢查询日志

javascript
// 记录慢查询 mongoose.connection.on('connected', () => { mongoose.connection.db.admin().command({ profile: 1, slowms: 100 // 超过100ms的查询 }); });

最佳实践总结

  1. 连接管理:使用连接池,避免频繁连接断开
  2. 索引优化:为常用查询创建合适的索引
  3. 查询优化:使用 lean()、选择性查询、限制结果
  4. 批量操作:使用批量操作代替多次单条操作
  5. 缓存策略:合理使用查询缓存和应用层缓存
  6. 数据模型:根据访问模式选择嵌入或引用
  7. 监控调优:持续监控查询性能,及时优化
  8. 避免 N+1 查询:合理设计数据结构,避免循环查询
标签:Mongoose