MongoDB通知清理查询优化及多查询合并执行咨询
优化方案与合并查询实现
1. 先创建高性能复合索引
大数据量下索引是核心优化点,创建以下复合索引,覆盖查询的过滤、分组、排序全场景,避免全表扫描:
db.persistentEvent.createIndex({ notificationClass: 1, sourceObjectIdentifier: 1, notificationType: 1, creationTime: 1, deliveryTime: 1 })
2. 修正分组逻辑,正确获取需保留的通知ID
原查询的$sort阶段放在$project之后,因$project已丢弃sourceObjectIdentifier和creationTime字段,排序完全无效。且要保留最早通知,需先按creationTime升序排序,再分组取每组第一条数据的ID:
db.persistentEvent.aggregate([ { "$match": { "notificationClass": "category" } }, { "$sort": { "sourceObjectIdentifier": 1, "notificationType": 1, "creationTime": 1 } }, { "$group": { "_id": { "sourceObjectIdentifier": "$sourceObjectIdentifier", "notificationType": "$notificationType" }, "keepNotificationId": { "$first": "$notificationId" } } }, { "$project": { "_id": 0, "keepNotificationId": 1 } } ])
3. 合并查询为单步删除(无需分两次执行)
MongoDB 4.2及以上版本支持用聚合管道作为deleteMany的过滤条件,直接在数据库层面完成筛选+删除操作,避免将大量ID拉取到客户端执行$nin(这是大数据量下耗时的核心原因)。
高效合并删除命令
// 替换为你的实际时间变量 const dateFrom = ISODate("2024-01-01T00:00:00Z"); const dateTo = ISODate("2024-06-01T00:00:00Z"); db.persistentEvent.deleteMany([ // 基础过滤条件 { "$match": { "notificationClass": "category", "deliveryTime": { "$gt": dateFrom }, "creationTime": { "$lt": dateTo } } }, // 关联同组文档,获取组内最早的通知ID { "$lookup": { "from": "persistentEvent", "let": { "sourceId": "$sourceObjectIdentifier", "type": "$notificationType" }, "pipeline": [ { "$match": { "$expr": { "$and": [ { "$eq": ["$sourceObjectIdentifier", "$$sourceId"] }, { "$eq": ["$notificationType", "$$type"] }, { "$eq": ["$notificationClass", "category"] } ] } } }, { "$sort": { "creationTime": 1 } }, { "$limit": 1 }, { "$project": { "_id": 0, "notificationId": 1 } } ], "as": "groupEarliest" } }, // 筛选出不属于组内最早的文档 { "$match": { "$expr": { "$ne": ["$notificationId", { "$arrayElemAt": ["$groupEarliest.notificationId", 0] }] } } } ])
额外优化建议
- 若
notificationId就是文档的_id,直接用_id替代,减少字段存储和查询开销 - 若每日删除数据量极大,可分批删除(比如每次删1000条),避免长时间锁表
- 定期清理无效索引,保证索引使用效率
内容的提问来源于stack exchange,提问作者sks
相关产品推荐
相关产品推荐

