我们在日常运营中会积累大量的数据,有时候需要把这些数据归档。
对于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天
);
选择哪种方案主要取决于数据量大小、业务要求和系统资源情况。