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

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

相关推荐
bcbnb3 小时前
HTTP抓包分析神器,Fiddler使用教程、代理设置与HTTPS调试全指南(开发者实战分享)
后端
Gogo8164 小时前
从 Spring Boot 到 NestJS:模块化设计的哲学差异
java·后端·nestjs
QX_hao4 小时前
【Go】--log模块的使用
开发语言·后端·golang
JohnYan4 小时前
工作笔记 - WSL端口映射
后端·网络协议·visual studio code
小陈不好吃4 小时前
Spring Boot配置文件加载顺序详解(含Nacos配置中心机制)
java·开发语言·后端·spring
IT_陈寒4 小时前
Vite性能优化实战:5个被低估的配置让你的开发效率提升50%
前端·人工智能·后端
IT_陈寒4 小时前
Java性能调优的7个被低估的技巧:从代码到JVM全链路优化
前端·人工智能·后端
Bony-5 小时前
Go语言并发编程完全指南-进阶版
开发语言·后端·golang
无名之辈J5 小时前
库存预扣减之后,用户订单超时之后补偿库存的方案
后端
勇者无畏4046 小时前
基于 Spring AI Alibaba 搭建 Text-To-SQL 智能系统(初始化)
java·后端·spring