每次我们使用collection.remove()
从MongoDB中删除大量数据时,这会使数据库变得非常慢,最终我们的Web服务器会崩溃。我相信这是因为删除操作会将集合锁定更长的时间。
我们有一个查询,它为我们提供了要删除的所有文档。但是查询不包含日期/时间字段,因此我们无法使用TTL索引。
有没有办法以nice
方式删除数据,不时释放锁?
答案 0 :(得分:16)
批量操作可能在这里有所帮助。无序bulk.find(queryDoc).remove()
基本上是针对大量操作优化的db.collection.remove(queryDoc)
版本。它的使用非常简单:
var bulk = db.yourCollection.initializeUnorderedBulkOp()
bulk.find(yourQuery).remove()
bulk.execute()
有关详细信息,请参阅Bulk.find().remove() in the MongoDB docs。
这种方法背后的想法不是加快移除速度,而是减少负载。在我的测试中,负载减少了一半,并且比db.collection.remove(query)
花费的时间略短。
但是,删除操作不应该将您的实例陈旧到冻结点。我在我5岁的MacBook上测试了12M文件的删除情况,虽然它给它带来了一些负担,但它远远没有冻结,花了大约10分钟。但是,我用于查询的字段已编入索引。
这使我得出结论,可能您可能正在体验集合扫描。如果我是对的,则会发生以下情况:您的查询包含未包含在索引中或无法构造索引交集的字段或字段组合。这会强制有问题的mongod为数据库中的每个文档 从磁盘 查找,访问和读取字段。
因此,在删除操作之前在后台创建包含查询中每个字段的索引可能会有所帮助,但这是违反直觉的。
db.collection.createIndex(
{firstFieldYouQueryBy:1,...,NthFieldYouQueryBy:1},
{background:true}
)
虽然这个操作将在后台完成,但shell会阻塞。 这可能需要一段时间。您可以通过打开第二个shell来查看状态并使用:
db.currentOp()
(你需要搜索一下)。
创建索引时(您可以使用db.collection.getIndices()
进行检查),您的删除操作应该更高效,因此更快。完成批量删除后,如果不需要,您当然可以删除索引。
使用索引,可以防止收集扫描,从而大大加快删除速度。
显而易见的是,首先创建索引并在索引就绪后发出bulk命令是有意义的。