MongoDB 删除数据方案

我们在日常运营中会积累大量的数据,有时候需要把这些数据归档。

对于MongoDB来说,如果要快速删除大量数据,这里有几种方法可以考虑:

1 deleteMany() - 基础方案

php 复制代码
// 基本用法
db.collection.deleteMany({ status: "inactive" })

// 带条件删除
db.collection.deleteMany({ 
  createdAt: { $lt: new Date("2023-01-01") },
  status: { $in: ["deleted", "expired"] }
})

优点:

  • 简单易用
  • 支持复杂查询条件
  • 返回删除数量

缺点:

  • 删除大量数据时可能很慢
  • 可能阻塞其他操作
  • 内存消耗较大

2 批量删除 - 推荐方案

ini 复制代码
// 分批删除,避免长时间阻塞
function batchDelete(collection, filter, batchSize = 1000) {
  let deletedCount = 0;
  let result;
  
  do {
    result = db[collection].deleteMany(filter, { limit: batchSize });
    deletedCount += result.deletedCount;
    print(`Deleted ${deletedCount} documents so far...`);
    
    // 可选:添加短暂延迟,减少系统压力
    sleep(100);
  } while (result.deletedCount > 0);
  
  return deletedCount;
}

// 使用示例
batchDelete("myCollection", { status: "inactive" }, 5000);

3 使用索引优化

php 复制代码
// 确保查询条件有索引支持
db.collection.createIndex({ status: 1, createdAt: 1 });

// 然后执行删除
db.collection.deleteMany({ 
  status: "inactive", 
  createdAt: { $lt: new Date("2023-01-01") }
});

4 Drop + Recreate - 最快方案(特殊情况)

如果要删除集合中的大部分数据:

php 复制代码
// 如果删除90%以上的数据,考虑这种方式
// 1. 将需要保留的数据导出到新集合
db.oldCollection.aggregate([
  { $match: { status: "active" } },  // 保留条件
  { $out: "newCollection" }
]);

// 2. 删除原集合
db.oldCollection.drop();

// 3. 重命名新集合
db.newCollection.renameCollection("oldCollection");

// 4. 重建索引
db.oldCollection.createIndex({ status: 1 });

5 使用 bulkWrite 优化

ini 复制代码
// 对于有特定_id的批量删除
const idsToDelete = [ObjectId("..."), ObjectId("..."), /* ... */];
const batchSize = 1000;

for (let i = 0; i < idsToDelete.length; i += batchSize) {
  const batch = idsToDelete.slice(i, i + batchSize);
  const operations = batch.map(id => ({
    deleteOne: { filter: { _id: id } }
  }));
  
  db.collection.bulkWrite(operations, { ordered: false });
}

6 性能优化建议

6.1 使用合适的写关注

php 复制代码
db.collection.deleteMany(
  { status: "inactive" },
  { writeConcern: { w: 1, j: false } }  // 减少写确认要求
);

6.2 在低峰期执行

scss 复制代码
// 添加时间检查,在业务低峰期执行
const hour = new Date().getHours();
if (hour >= 2 && hour <= 6) {  // 凌晨2-6点执行
  db.collection.deleteMany({ status: "inactive" });
}

6.3 监控执行进度

javascript 复制代码
// 先统计总数
const totalCount = db.collection.countDocuments({ status: "inactive" });
console.log(`Total documents to delete: ${totalCount}`);

// 执行删除并监控
const result = db.collection.deleteMany({ status: "inactive" });
console.log(`Deleted: ${result.deletedCount} documents`);

总结

  • 小量数据(< 10万) : 直接使用 deleteMany()
  • 中等数据量(10万-100万) : 使用批量删除
  • 大量数据(> 100万) : 考虑 drop+recreate 或分片删除
  • 定期清理: 建议使用 TTL 索引自动删除过期数据
json 复制代码
// TTL索引示例 - 自动删除30天前的数据
db.collection.createIndex(
  { "createdAt": 1 }, 
  { expireAfterSeconds: 30 * 24 * 60 * 60 }  // 30天
);

选择哪种方案主要取决于数据量大小、业务要求和系统资源情况。

相关推荐
Apifox.3 小时前
Apifox 9 月更新| AI 生成接口测试用例、在线文档调试能力全面升级、内置更多 HTTP 状态码、支持将目录转换为模块
前端·人工智能·后端·http·ai·测试用例·postman
绝无仅有4 小时前
消息队列mq面试经典问题与解答总结
后端·面试·github
绝无仅有4 小时前
数据库mysql报错追踪与解决总结
后端·面试·github
Codelinghu4 小时前
快速入门SpringAI-SpringAI Alibaba实战
后端
ZhengEnCi4 小时前
@Component 注解完全指南-从入门到精通的 Spring 核心组件管理
spring boot·后端
Penge6664 小时前
MySQL-隐式类型转换的 “隐形陷阱”
后端·mysql
ZhengEnCi4 小时前
@ConfigurationProperties 注解完全指南-从入门到精通 Spring 配置属性绑定
spring boot·后端
A阳俊yi5 小时前
Spring——事件机制
java·后端·spring
码事漫谈5 小时前
noexcept 的微妙平衡:性能、正确性与接口契约
后端
码事漫谈5 小时前
超越 std::unique_ptr:探讨自定义删除器的真正力量
后端