【问题标题】:Does MongoDB $set write just the field or the whole document?MongoDB $set 是只写字段还是整个文档?
【发布时间】:2014-04-17 22:07:30
【问题描述】:

我相信字段上的$inc 只会更改该字段,而不会重写整个文档。

我的问题是字符串字段上的$set(假设字符串的长度相同)的行为方式是否相同。还是整个文档都被重写了?

通过扩展,副本集是复制整个记录还是只是复制增量?

我很欣赏这是一个微优化问题。

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    这取决于。如果磁盘上分配的块中有空间,它将就地写入。如果没有空间,即文档超出其当前分配的空间,MongoDB 分配一个新空间并将文档移动到这个新位置。

    如果您想最小化文档移动,您可以设置填充因子。然后MongoDB 通过添加此paddingFactor 来调整记录分配的大小,以便文档有增长空间。更多关于 Record Padding

    关于副本集:副本集使用oplog(操作日志)进行操作。 Oplog 是一个有上限的集合(固定大小的集合,当它达到最大大小时会自动覆盖其最旧的条目),它会记录所有修改数据库中数据的操作。辅助节点以异步方式复制和应用这些操作。任何副本集成员都可以从任何其他副本集成员的 oplog 中导入条目。

    这意味着当您插入一个新文档时,该确切的更新操作将复制到其他副本集成员并单独执行。涉及同一文档的任何后续更新都会发生同样的事情。这是关于 MongoDB Replica Set Oplog 的信息。

    【讨论】:

      【解决方案2】:

      TL;DR:$inc 保证就地更新,$set 不保证,但在非常特殊的情况下也可以就地完成。

      详情

      这有两个方面:

      1. 它是如何通过电线的?

        信息作为操作发送,$set 仍然是$set,所以它是一个增量。对于用于复制的 oplog 也是如此。这样,使用$set在带宽方面效率更高。

      2. 它是如何在磁盘上更新的?

        当且仅当 键(字段)已经存在时,MongoDB 才会执行 就地更新,因此当您向文档添加新字段时,该字段会更大操作,而不仅仅是为现有字段分配不同的值。

        即便如此,这些值也必须具有相同的大小,并且必须不改变类型,并且它们必须是类型double, long, int or bool ,否则它不是当前的就地更新。

      我不确定后者在实践中的重要性如何在实践中,但服务器肯定会为两者使用完全不同的代码路径,因此它可能会导致字段重新排序。对于非常大的文档,这可能会导致性能上的显着差异。

      这表明$inc 非常不同,因为它只允许肯定就地的操作,因为$inc 只对数字类型进行操作,自然不能更改大小或类型。

      【讨论】:

        【解决方案3】:

        我的问题是是否在字符串字段上设置 $set

        假设大小没有变化,如您所说,MongoDB 只会更新内存中的该字段,然后将该字段保存回文档中。

        通过扩展,副本集是复制整个记录还是只是复制增量?

        副本集通过从 oplog 中挑选将相同的 op 应用到自己上,就像主集所做的那样。

        因此,如果主应用了就地更新,那么该集合的所有成员也将应用。

        【讨论】:

          猜你喜欢
          • 2023-04-03
          • 1970-01-01
          • 2021-03-12
          • 1970-01-01
          • 2018-03-31
          • 2021-02-21
          • 1970-01-01
          相关资源
          最近更新 更多