DeleteManyAsync删除MongoDB文档时会锁定集合吗?

3

我想使用DeleteManyAsync方法来删除多个文档。我将遇到删除大集合的情况。同时,我希望我的新文档被插入。我想知道在触发DeleteManyAsync时我的数据库集合是否会被锁定

这是我想要使用的代码:

 List<MyDocument> list= new List<MyDocument>();
 var filter = Builders<MyDocument>.Filter.In("_id", vl.Select(i => i.InternalId));
 await _context?.MyDocuments?.DeleteManyAsync(filter);
1个回答

6
MongoDB的锁是一个低级别的问题,由数据库服务器处理。作为使用驱动程序编写客户端应用程序的程序员,您不需要过多关注数据库锁。

我的意思是,在使用C#驱动程序时,您不会注意到与在同一集合上执行的并发写操作相关的任何问题。锁由存储引擎处理,而不是在客户端应用程序级别使用的驱动程序。

如果您查看this documentation,您可以阅读到在同一集合上存在冲突写操作的情况下,存储引擎将在服务器级别重试该操作:

当存储引擎检测到两个操作之间的冲突时,其中一个将导致写冲突,从而使MongoDB在服务器级别上透明地重试该操作

因此,再次强调,并发问题在服务器级别上得到处理。

如果您需要应用程序具有高度可扩展性,那么应该尽可能地设计系统以避免在同一集合上进行并发写操作。如上所述,锁由存储引擎处理,以保持数据的正确性,但锁会降低系统的整体可扩展性。因此,如果可扩展性在您的情况下非常重要,则应仔细设计系统,并尽可能避免在数据库级别上争用资源。
在客户端应用程序级别,您只需要决定是否在写操作失败时重试。
有时候,您可以安全地重试失败的操作,而其他时候则不行(例如:在某些情况下,您将在数据库级别上拥有重复的数据。一个好的防护措施是使用唯一索引)。
作为经验法则,幂等写操作在失败的情况下可以安全地重试(因为多次应用它们没有任何副作用)。换句话说,尽可能使写操作幂等:这样,您始终可以安全地重试失败的写操作。
如果您需要关于mongo C#驱动程序错误处理的指导,您可以查看this documentation
2020年7月25日更新
根据作者的评论,似乎主要关注的不是实际的数据库锁定策略,而是删除性能。
在这种情况下,我会按照以下方式进行:
  • 始终优先选择执行单个数据库往返的命令(例如deleteMany),而不是发出多个单个命令(例如deleteOne)。通过执行单次往返,您将最小化延迟成本并执行单个数据库命令。这更有效率。
  • 当使用deleteMany命令时,请务必使用适当的索引筛选文档,以避免在查找要删除的文档时进行集合扫描。
  • 如果您测量并且确定瓶颈是deleteMany速度,请考虑比较deleteMany命令与等效批量写操作的性能。我从未尝试过,所以我对实际速度比较没有任何想法。我的感觉是可能根本没有区别,因为我怀疑在幕后deleteMany执行批量写入。我对此一无所知,这只是一种感觉。
  • 考虑更改设计,以利用TTL索引功能自动删除文档,当满足某些过期条件时。这并非总是可行,但在适用时可以很方便。
  • 如果您将删除操作作为某种数据清理任务的一部分执行,请考虑定期安排执行数据清理操作的作业,但在用户的非工作时间之外

感谢您提供的信息性回复,非常有帮助。在我的情况下,我只是担心如果我使用DeleteManyAsync删除对象可能需要一些时间。同时,如果我有一个插入操作,它不会出现在数据库中(因为被锁定)。这就是为什么我想知道是否应该循环每个要删除的元素还是一次性删除所有内容。 - mike
1
@mike 我已经更新了我的答案,涉及到了你在评论中提出的点。 - Enrico Massone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接