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天
);

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

相关推荐
Tony Bai9 小时前
“Go 2,请不要发生!”:如果 Go 变成了“缝合怪”,你还会爱它吗?
开发语言·后端·golang
Victor35610 小时前
Hibernate(91)如何在数据库回归测试中使用Hibernate?
后端
Victor35610 小时前
MongoDB(1)什么是MongoDB?
后端
Victor35616 小时前
https://editor.csdn.net/md/?articleId=139321571&spm=1011.2415.3001.9698
后端
Victor35616 小时前
Hibernate(89)如何在压力测试中使用Hibernate?
后端
灰子学技术18 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
Gogo81619 小时前
BigInt 与 Number 的爱恨情仇,为何大佬都劝你“能用 Number 就别用 BigInt”?
后端
fuquxiaoguang19 小时前
深入浅出:使用MDC构建SpringBoot全链路请求追踪系统
java·spring boot·后端·调用链分析
毕设源码_廖学姐20 小时前
计算机毕业设计springboot招聘系统网站 基于SpringBoot的在线人才对接平台 SpringBoot驱动的智能求职与招聘服务网
spring boot·后端·课程设计
野犬寒鸦21 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法