我对在MongoDB中同时进行$inc
更新有疑问。在UpdateOne
和findOneAndUpdate
的手册页中,提到了应用并发上插的微妙之处,并且始终建议使用唯一索引进行更新匹配。基本思想是,如果两个进程尝试更新不存在的某个文档,而一个进程在另一个进程完成查询之前先完成查询,那么在没有唯一索引的情况下,每个进程都会创建一个新文档,从而导致重复。在这种情况下,确实定义唯一索引将防止它发生。
另一方面,如果我的更新是增量操作,我想知道唯一索引是否可以节省一天的时间。让我们考虑一个简化的投票示例,其中的文档如下所示:
{'name': 'Alice', 'votes': 0},
{'name': 'Bob', 'votes': 0}
...
假设name
已被唯一索引(假定没有同名候选人)。假设许多进程正在收集投票并进行以下更新:
collection.update_one({'name': name}, {'$inc': {'votes': 1}}, upsert=False)
其中name
是另一个地方定义的python变量。我想知道手册(see example)中的相同论点是否可以在这里适用。
想象一下,爱丽丝得到5票。进程A和进程B都希望将爱丽丝的票数增加1。如果两个进程正确配合,我们希望爱丽丝获得7票。但是,如果进程A在B找到它之后但B开始进行增量之前找到了Alice的文档,则进程A应该知道Alice拥有5票,与进程B相同。因此,即使A将在B之后进行修改,释放写锁,它将选票更改为5 + 1 = 6票,而不是7。
我把整个事情弄错了吗?我认为这与$inc
的工作方式以及单文档更新的实际工作方式有关,但是我不确定,因为:
$inc
手册页和
为此要设计一个实验并不容易,因为要使两个过程发生冲突,似乎有必要拥有一个大型数据集。对于小型数据集,一个过程很容易找到所需的文档并在另一个过程出现之前对其进行修改。实际上,我对2位候选人进行了投票实验,无论姓名是否具有唯一索引,都不会出错。
任何关于定位和更新如何与updateOne
和findOneAndUpdate
一起工作以及$inc
操作如何工作的见解。
干杯!
答案 0 :(得分:0)
要阅读和写,您需要了解MongoDB中的锁定机制。
从MongoDB 3.2开始,WiredTiger存储引擎是默认存储引擎。
基本内容
WiredTiger存储引擎将文档级别锁定引入 MongoDB,这意味着写入不再阻止集合或数据库。 虽然3.0中的MMAP带来了集合级别的锁定,但多次写入 相同的集合仍将导致写入顺序应用 并可能会饿死集合中的读取,因为读取必须等待 写完成。 WiredTiger摆脱了允许的限制 对同一集合同时进行多次写入。 这意味着使用CPU进行读写缩放,而在MMAP中 由于锁减少了CPU扩展的上限,因此 吞吐量。
根据 WiredTiger存储引擎
一旦发出写入请求,所有读取器都会被阻塞,直到写入 完成特定收藏。
参考链接:1。OverviewLink,2。aboutStorageEngin
发现并修改行为
Upsert and Unique Index
当findAndModify命令包含upsert:true选项时, 查询字段未唯一索引,该命令可以插入一个 在某些情况下需要多次记录。
为防止创建多个重复文档,请在名称字段上创建唯一索引。有了唯一索引后,多个findAndModify命令将表现出以下行为之一:
恰好一个findAndModify成功插入了一个新文档。零或 更多findAndModify命令更新新插入的文档。零 或多个findAndModify命令在尝试插入 重复。如果命令由于唯一索引约束而失败 违反,您可以重试该命令。缺少文档的删除, 重试应该不会失败。
参考链接:here