Amazon DocumentDB 性能优化 #

一、性能优化概述 #

1.1 优化维度 #

text
性能优化维度:
├── 查询优化
│   ├── 查询语句优化
│   ├── 索引使用
│   └── 执行计划分析
│
├── 索引优化
│   ├── 索引设计
│   ├── 索引维护
│   └── 索引监控
│
├── 连接优化
│   ├── 连接池配置
│   ├── 连接管理
│   └── 连接复用
│
└── 配置优化
    ├── 实例规格
    ├── 参数配置
    └── 资源分配

1.2 性能基准 #

text
建立性能基准:
├── 记录正常性能指标
├── 监控关键指标
├── 设置性能阈值
├── 定期性能测试
└── 持续优化改进

二、查询优化 #

2.1 使用explain分析 #

javascript
// 分析查询执行计划
db.users.find({ email: "test@example.com" }).explain("executionStats")

// 关键指标
{
  "executionStats": {
    "totalDocsExamined": 1,      // 扫描文档数
    "totalKeysExamined": 1,      // 扫描索引键数
    "executionTimeMillis": 0,    // 执行时间
    "indexUsed": "email_1"       // 使用的索引
  }
}

// 理想情况
// totalDocsExamined ≈ 返回文档数
// totalKeysExamined ≈ totalDocsExamined

2.2 查询优化技巧 #

javascript
// 1. 使用索引覆盖查询
db.users.find(
  { email: "test@example.com" },
  { _id: 0, email: 1, name: 1 }  // 只返回索引字段
)

// 2. 限制返回字段
db.users.find(
  { status: "active" },
  { name: 1, email: 1 }  // 只返回需要的字段
)

// 3. 使用投影减少数据传输
db.orders.find(
  { status: "completed" },
  { orderNo: 1, amount: 1 }
)

// 4. 避免使用$or,使用$in代替
// 不推荐
db.users.find({
  $or: [
    { status: "active" },
    { status: "pending" }
  ]
})

// 推荐
db.users.find({
  status: { $in: ["active", "pending"] }
})

// 5. 避免使用$nin和$ne
// 不推荐
db.users.find({ status: { $ne: "deleted" } })

// 推荐
db.users.find({ 
  status: { $in: ["active", "pending", "inactive"] }
})

2.3 排序优化 #

javascript
// 排序使用索引
db.orders.createIndex({ status: 1, createdAt: -1 })

// 使用索引排序
db.orders.find({ status: "completed" }).sort({ createdAt: -1 })

// 避免内存排序
// 如果排序字段没有索引,使用allowDiskUse
db.orders.find({}).sort({ amount: -1 }).allowDiskUse(true)

2.4 分页优化 #

javascript
// 使用游标分页代替skip
// 不推荐:深度分页性能差
db.orders.find({}).skip(10000).limit(10)

// 推荐:使用游标分页
function findWithCursor(lastId, limit = 10) {
  const query = lastId 
    ? { _id: { $gt: lastId } }
    : {};
  
  return db.orders.find(query)
    .sort({ _id: 1 })
    .limit(limit)
    .toArray();
}

三、索引优化 #

3.1 索引设计原则 #

text
ESR规则:
├── Equality(等值查询字段在前)
├── Sort(排序字段其次)
└── Range(范围查询字段最后)

示例:
查询:{ status: "active", createdAt: { $gte: date } }
排序:{ amount: -1 }
索引:{ status: 1, amount: -1, createdAt: 1 }

3.2 索引创建策略 #

javascript
// 1. 为常用查询字段创建索引
db.users.createIndex({ email: 1 })

// 2. 创建复合索引
db.orders.createIndex({ 
  status: 1, 
  createdAt: -1, 
  amount: -1 
})

// 3. 使用部分索引减少大小
db.orders.createIndex(
  { status: 1, createdAt: -1 },
  { 
    partialFilterExpression: {
      status: { $in: ["pending", "processing"] }
    }
  }
)

// 4. 使用稀疏索引
db.users.createIndex(
  { nickname: 1 },
  { sparse: true }
)

3.3 索引监控 #

javascript
// 查看索引使用情况
db.users.aggregate([
  { $indexStats: {} },
  { $sort: { "accesses.ops": -1 } }
])

// 找出未使用的索引
db.users.aggregate([
  { $indexStats: {} },
  { $match: { "accesses.ops": 0 } }
])

// 查看索引大小
db.users.totalIndexSize()

3.4 索引维护 #

javascript
// 删除未使用的索引
db.users.dropIndex("unused_index_name")

// 重建索引(谨慎使用)
db.users.reIndex()

// 查看索引构建进度
db.currentOp({
  $or: [
    { op: "command", "command.createIndexes": { $exists: true } },
    { op: "none", ns: /system\.indexes/ }
  ]
})

四、连接池优化 #

4.1 连接池配置 #

javascript
// Node.js连接池配置
const client = new MongoClient(uri, {
  maxPoolSize: 100,           // 最大连接数
  minPoolSize: 10,            // 最小连接数
  maxIdleTimeMS: 60000,       // 最大空闲时间
  waitQueueTimeoutMS: 5000,   // 等待超时
  connectTimeoutMS: 10000,    // 连接超时
  socketTimeoutMS: 0,         // Socket超时
  serverSelectionTimeoutMS: 5000  // 服务器选择超时
});

4.2 连接池最佳实践 #

text
连接池建议:
├── maxPoolSize:根据实例规格设置
│   ├── db.r6g.large:50-100
│   ├── db.r6g.xlarge:100-200
│   └── db.r6g.2xlarge:200-400
│
├── minPoolSize:保持一定数量的连接
├── maxIdleTimeMS:避免长时间空闲
├── 合理设置超时时间
└── 监控连接使用情况

4.3 连接管理 #

javascript
// 连接管理最佳实践
class DatabaseManager {
  constructor() {
    this.client = null;
  }
  
  async connect() {
    if (!this.client) {
      this.client = new MongoClient(uri, {
        maxPoolSize: 50,
        minPoolSize: 5
      });
      await this.client.connect();
    }
    return this.client;
  }
  
  async disconnect() {
    if (this.client) {
      await this.client.close();
      this.client = null;
    }
  }
  
  getClient() {
    if (!this.client) {
      throw new Error('Database not connected');
    }
    return this.client;
  }
}

// 单例模式
const dbManager = new DatabaseManager();

五、写入优化 #

5.1 批量写入 #

javascript
// 使用批量写入代替循环单条写入
// 不推荐
for (const doc of documents) {
  await db.users.insertOne(doc);
}

// 推荐
await db.users.insertMany(documents);

// 批量大小建议:1000-5000
const batchSize = 1000;
for (let i = 0; i < documents.length; i += batchSize) {
  const batch = documents.slice(i, i + batchSize);
  await db.users.insertMany(batch, { ordered: false });
}

5.2 写关注优化 #

javascript
// 根据场景选择写关注
// 高性能场景
db.users.insertOne(
  { name: "张三" },
  { writeConcern: { w: 1 } }
);

// 高可靠场景
db.users.insertOne(
  { name: "张三" },
  { writeConcern: { w: "majority", j: true } }
);

5.3 索引影响 #

text
索引对写入的影响:
├── 每个索引增加写入开销
├── 索引越多,写入越慢
├── 批量导入时考虑删除索引
└── 导入后重建索引

六、读取优化 #

6.1 读偏好设置 #

javascript
// 读偏好设置
// 从副本读取
db.users.find({}).readPref("secondaryPreferred");

// 读偏好选项
const readPreferences = {
  "primary": "只从主实例读取",
  "primaryPreferred": "优先主实例",
  "secondary": "只从副本读取",
  "secondaryPreferred": "优先副本",
  "nearest": "延迟最低的节点"
};

6.2 缓存优化 #

text
缓存策略:
├── 使用应用层缓存(Redis)
├── 缓存热点数据
├── 设置合理的过期时间
├── 实现缓存更新机制
└── 监控缓存命中率

6.3 查询结果缓存 #

javascript
// 实现简单的查询缓存
class QueryCache {
  constructor(ttl = 60000) {
    this.cache = new Map();
    this.ttl = ttl;
  }
  
  async get(key, queryFn) {
    const cached = this.cache.get(key);
    
    if (cached && Date.now() - cached.time < this.ttl) {
      return cached.data;
    }
    
    const data = await queryFn();
    this.cache.set(key, { data, time: Date.now() });
    return data;
  }
  
  invalidate(key) {
    this.cache.delete(key);
  }
}

// 使用示例
const cache = new QueryCache();
const users = await cache.get('active_users', () => 
  db.users.find({ status: 'active' }).toArray()
);

七、配置优化 #

7.1 实例规格选择 #

场景 推荐规格 说明
开发测试 db.t3.medium 成本优化
小型生产 db.r6g.large 入门级生产
中型生产 db.r6g.xlarge 中等负载
大型生产 db.r6g.2xlarge 高负载
超大规模 db.r6g.4xlarge 极高负载

7.2 副本配置 #

text
副本配置建议:
├── 生产环境至少2个副本
├── 跨可用区部署
├── 根据读负载调整副本数
├── 监控副本延迟
└── 合理设置故障转移优先级

7.3 参数优化 #

bash
# 常用参数优化
# 慢查询阈值
aws docdb modify-db-cluster-parameter-group \
  --db-cluster-parameter-group-name custom-params \
  --parameters "ParameterName=slow_op_threshold_ms,ParameterValue=50,ApplyMethod=immediate"

# 启用性能分析
aws docdb modify-db-cluster \
  --db-cluster-identifier my-cluster \
  --enable-cloudwatch-logs-exports '["profiler"]' \
  --apply-immediately

八、监控与诊断 #

8.1 性能监控指标 #

text
关键监控指标:
├── CPUUtilization - CPU使用率
├── FreeableMemory - 可用内存
├── DatabaseConnections - 连接数
├── ReadLatency/WriteLatency - 读写延迟
├── BufferCacheHitRatio - 缓存命中率
├── ReplicationLag - 复制延迟
└── QueryThroughput - 查询吞吐量

8.2 慢查询分析 #

javascript
// 分析慢查询
db.system.profile.find({
  millis: { $gt: 100 }
}).sort({ ts: -1 }).limit(10)

// 聚合分析慢查询
db.system.profile.aggregate([
  { $match: { millis: { $gt: 100 } } },
  { $group: {
    _id: "$command.find",
    count: { $sum: 1 },
    avgTime: { $avg: "$millis" },
    maxTime: { $max: "$millis" }
  }},
  { $sort: { avgTime: -1 } }
])

8.3 性能诊断工具 #

text
诊断工具:
├── explain() - 查询计划分析
├── $indexStats - 索引使用统计
├── CloudWatch - 性能监控
├── Performance Insights - 性能洞察
└── 审计日志 - 操作审计

九、性能测试 #

9.1 基准测试 #

javascript
// 简单的性能测试
async function benchmarkQuery(query, iterations = 100) {
  const times = [];
  
  for (let i = 0; i < iterations; i++) {
    const start = Date.now();
    await query();
    times.push(Date.now() - start);
  }
  
  return {
    avg: times.reduce((a, b) => a + b) / times.length,
    min: Math.min(...times),
    max: Math.max(...times),
    p95: times.sort((a, b) => a - b)[Math.floor(times.length * 0.95)]
  };
}

// 使用示例
const result = await benchmarkQuery(() => 
  db.users.find({ email: "test@example.com" }).toArray()
);
console.log(result);

9.2 负载测试 #

text
负载测试建议:
├── 模拟真实场景
├── 逐步增加负载
├── 监控关键指标
├── 记录性能数据
└── 分析瓶颈

十、总结 #

10.1 优化要点 #

维度 优化方法
查询 使用索引、优化语句、减少扫描
索引 合理设计、定期维护、监控使用
连接 连接池、复用连接、监控连接
配置 合适规格、参数优化、资源分配

10.2 最佳实践总结 #

text
性能优化最佳实践:
├── 建立性能基准
├── 持续监控分析
├── 定期优化调整
├── 测试验证效果
└── 文档记录经验

下一步,让我们学习迁移指南!

最后更新:2026-03-27