每次我们使用 collection.remove()
从 MongoDB 中删除大量数据时,这都会使数据库变得如此缓慢,最终导致我们的 Web 服务器出现故障。我相信这是因为删除操作将集合锁定了更长的时间。
我们有一个查询,它提供了我们想要删除的所有文档。但是查询不包含日期/时间字段,因此我们不能使用 TTL 索引。
有没有办法以 nice
的方式删除数据,不时释放锁?
最佳答案
使用批量操作
批量操作可能在这里有所帮助。无序的 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()
检查),您的删除操作应该更有效,因此更快。批量删除完成后,如果不需要,当然可以删除索引。
使用索引,您可以防止收集扫描,从而大大加快删除速度。
结合这两种方法
显然,首先创建索引并在索引准备好后发出批量命令是有意义的。
关于mongodb - 如何从 MongoDB 中删除数据而不使其停止运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33123008/