bounty将在3天后过期。回答此问题可获得+500声望奖励。Rasto希望引起更多人关注此问题。
MongoDB聚合管道的各个阶段总是按顺序执行的。管道处理的文档是否可以在各个阶段之间更改?例如,如果 stage1 与 * collection 1 * 中的一些文档匹配,* stage 2 * 与 * collection 2 * 中的一些文档匹配,那么 * collection 2 * 中的一些文档是否可以在 stage1 期间或之后写入(即在 * stage 2 * 之前)?如果是,是否可以预防此类行为?
- 为什么这是重要的:* 说 * stage 2 * 是一个
$lookup
阶段。查找是NoSQL等价于SQL连接。在一个典型的SQL数据库中,连接查询与写入是隔离的。这意味着当连接被解析时,受连接影响的数据不能改变。我想知道我在MongoDB中是否有同样的保证。请注意,我来自noSQL世界(只是不是MongoDB),我很了解这种模式。没有必要建议复制数据,如果有这样的解决方案,我就不会问SO。
根据我的研究,MongoDb读查询获得了一个共享(读)锁,该锁阻止在同一个集合上写入,直到它被解析为止。然而,MongoDB文档没有提到任何关于聚合管道锁的内容。聚合管道是对它读取的所有集合都持有读(共享)锁呢?还是只对当前管道阶段使用的集合持有读(共享)锁?
- 更多上下文:* 我需要通过几个集合运行一个具有多个“联接”的“查询”。查询是动态生成的,我不知道预先将“联接”哪些集合。聚合管道是实现这一点的假定方式。但是,为了获得一致的“查询”数据,我需要确保管道的阶段之间没有交叉写入。
例如,$match
和$lookup
阶段之间的删除可能会删除其中一个连接(“查找”)文档,从而导致整个结果不正确/不一致。会发生这种情况吗?如何防止?
2条答案
按热度按时间ccrfmcuu1#
问:在管道执行期间,由聚合管道处理的MongoDB文档是否会受到外部写入的影响?
MongoDB事务支持事务级读关注和事务级写关注,客户端可以设置合适的 * 读写关注 * 级别,最严格的是 * 快照读关注 * 和 * 多数写关注 * 的组合。
要实现这一点,请在连接字符串/会话/事务 * 上设置readConcern=snapshot和writeConcern=majority(但不在数据库/集合/操作上设置,因为在事务下,数据库/集合/操作关注点设置将被忽略)。*
问:事务处理是否也适用于所有聚集管道阶段?
例如,根据mongodb文档,事务中允许
db.collection.aggregate()
,但某些阶段(例如$merge
)被排除在外。事务中支持的操作的完整列表:参考mongodb文件。holgip5t2#
@user20042973已经https://www.mongodb.com/docs/manual/reference/read-concern-snapshot/#mongodb-readconcern-readconcern.-snapshot-在第一条评论中提供了www.example.com的链接,但考虑到OP关于交易的后续评论和问题,似乎需要完整的答案才能清楚。
首先,事务都是关于写的,而不是读的。我怎么强调都不为过,所以请再读一遍--事务,或者mongodb是如何引入“多文档事务”的,它们是为了确保多个更新都有一个原子操作“提交”。在一个事务中所做的任何更改在事务之外都是不可见的,直到它被提交。并且当事务提交时,所有更改都将立即可见。文档:https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-atomicity
事务与OP询问的read**操作的一致性无关。聚合是一个读取操作,除非在最后指定$out或$merge阶段。
OP担心对数据库的任何并发写入都可能影响其聚合操作的结果,尤其是对于从主集合中查询其他集合以查找每个匹配文档的$lookup操作。
这是一个非常合理的考虑,因为MongoDB始终是最终一致的,并且不保证如果链接集合在聚合过程中被更改,这样的查找将返回相同的结果。一般来说,它甚至不保证唯一键在使用该索引的游标中是唯一的--如果文档被删除,然后具有相同唯一密钥的新密钥被插入,则有非零的机会来检索两者。
解决这一限制的工具称为“读关注点”,而不是“事务”。有许多读关注点可用于平衡速度和可靠性/一致性:https://www.mongodb.com/docs/v6.0/reference/read-concern/ OP是在最昂贵的一个--“快照”之后,正如ttps:www.mongodb.com/docs/v6.0/reference/read-concern-snapshot/所说:
快照是mongod示例中数据在特定时间点的完整副本。
mongod
在本文中拼写为“整体”-所有数据库、这些数据库中的集合、这些集合中的文档。查询中涉及“快照”的所有操作都是针对与节点接受查询时相同的数据版本执行的。
现在,就问题的这部分:
根据我的研究,MongoDb读查询获取一个共享(读)锁,该锁在解析之前阻止对同一集合的写操作。
最好能有这个声明的来源。到目前为止(v5.0+),聚合是无锁的,也就是说,即使其他操作持有集合上的独占X锁,它也不会被阻塞:https://www.mongodb.com/docs/manual/faq/concurrency/#what-are-lock-free-read-operations-
最后一点--如果这样的读隔离对业务至关重要,并且您必须保证严格的一致性,我建议考虑SQL数据库。它可能比快照查询性能更高。要考虑的因素要多得多,所以我将把它留给您。关键是mongo在最终一致性可接受的地方大放异彩。它在服务器会话内的因果一致性方面做得很好。这为更广泛的用例提供了足够的保证。我鼓励您测试它对快照查询的处理效果如何,特别是如果您正在运行多个查找,这本身在较大的数据集上可能会足够慢,甚至在不允许使用磁盘的情况下可能无法工作。