面试题答案
一键面试优化删除操作
- 索引优化:
- 确保
logs
集合在timestamp
和log_level
字段上有复合索引。可以通过以下命令创建复合索引:
db.logs.createIndex({timestamp: 1, log_level: 1});
- 复合索引能加快查询一年前且日志级别为'ERROR'的文档的速度,因为MongoDB可以利用索引快速定位到符合条件的文档,减少全表扫描的开销。
- 确保
- 批量删除:
- 不要一次性删除所有符合条件的数十亿条记录,而是采用批量删除的方式。可以使用循环来每次删除一定数量(例如1000条)的记录。以下是Node.js中使用MongoDB驱动的示例代码:
const { MongoClient } = require('mongodb'); const uri = "mongodb://localhost:27017"; const client = new MongoClient(uri); const dbName = "your_database_name"; const collectionName = "logs"; const currentDate = new Date(); const oneYearAgo = new Date(currentDate.getTime() - 365 * 24 * 60 * 60 * 1000); async function deleteOldErrorLogs() { try { await client.connect(); const db = client.db(dbName); const collection = db.collection(collectionName); let deletedCount = 0; while (true) { const result = await collection.deleteMany({ timestamp: { $lt: oneYearAgo }, log_level: 'ERROR' }, { limit: 1000 }); deletedCount += result.deletedCount; if (result.deletedCount === 0) { break; } } console.log(`Total deleted records: ${deletedCount}`); } finally { await client.close(); } } deleteOldErrorLogs();
- 批量删除可以减少单次操作对系统资源的占用,避免长时间锁定集合,影响其他读写操作。
恢复机制设计
- 记录删除操作:
- 在开始删除操作前,创建一个新的集合(例如
delete_logs
),用于记录每次删除操作的相关信息,包括删除的条件(时间范围、日志级别等)、删除的批次号、每次删除的文档数量等。在Node.js示例中,可以在每次删除成功后插入一条记录到delete_logs
集合:
const deleteLogCollection = db.collection('delete_logs'); await deleteLogCollection.insertOne({ batchNumber: batchNumber, deleteCondition: { timestamp: { $lt: oneYearAgo }, log_level: 'ERROR' }, deletedCount: result.deletedCount, operationTime: new Date() });
- 这样在遇到异常中断时,可以根据
delete_logs
集合中的记录来确定已经删除了哪些数据,从何处继续删除。
- 在开始删除操作前,创建一个新的集合(例如
- 使用事务(如果MongoDB版本支持):
- 对于支持多文档事务的MongoDB版本(4.0及以上),可以将删除操作放在事务中执行。例如,在Node.js中:
async function deleteOldErrorLogsWithTransaction() { try { await client.connect(); const session = client.startSession(); session.startTransaction(); const db = client.db(dbName); const collection = db.collection(collectionName); let deletedCount = 0; while (true) { const result = await collection.deleteMany({ timestamp: { $lt: oneYearAgo }, log_level: 'ERROR' }, { limit: 1000, session }); deletedCount += result.deletedCount; if (result.deletedCount === 0) { break; } } await session.commitTransaction(); console.log(`Total deleted records: ${deletedCount}`); } catch (error) { console.error('Transaction failed:', error); // 可以在这里添加处理异常的逻辑,例如记录错误信息到日志 } finally { await client.close(); } }
- 事务可以保证删除操作的原子性,如果在事务执行过程中遇到网络故障或其他异常,事务会自动回滚,确保数据的一致性。如果事务成功提交,那么所有删除操作都已生效。如果事务失败,可以根据上述记录删除操作的方法,从上次成功的批次继续执行删除操作。