【发布时间】:2019-08-30 17:25:59
【问题描述】:
这是一个 MongoDB 数据库的性能问题。
我在看书Learn MongoDB The Hard Way
上下文是如何用Comments 建模/设计BlogPost 的架构,讨论的解决方案是嵌入,如下所示:
{ postName: "..."
, comments:
[ { _id: ObjectId(d63a5725f79f7229ce384e1) author: "", text: ""} // each comment
, { _id: ObjectId(d63a5725f79f7229ce384e2) author: "", text: ""} // is a
, { _id: ObjectId(d63a5725f79f7229ce384e3) author: "", text: ""} // subDocument
]
}
在书中他的数据看起来不同,但实际上看起来像我上面的数据,因为推入 subDocuments 列表会创建 _id's
在第二个反驳论点中指出 这种嵌入方法的缺点 - 他这样说:
第二个方面与写入性能有关。随着 cmets 逐渐添加到博客文章中,MongoDB 很难预测在创建新文档时应用正确的文档填充。 MongoDB 需要为不断增长的文档分配新空间。此外,它还必须将文档复制到新的内存位置并更新所有索引。这可能会导致更多的 IO 负载,并可能影响整体写入性能。
提取这个:
此外,它还必须将文档复制到新的内存位置
问题1:这实际上是什么意思?
他指的是什么document..? BlogPost document 或 Comment document。
如果他指的是BlogPost document(似乎是这样),这是否意味着整个(小于 16MB)数据被完全重写/复制到硬盘上的新位置-disk,每次我插入一个子文档?
这就是 mongoDB 在后台的实际工作方式?有人可以确认或反驳这一点,因为每次写入移动/复制整个文档似乎是一件大事。尤其是当它向 16MB 的上限增长时。
问题2:
然后,当我更新一个简单的字段时会发生什么?说status: true 到status: false。整个文档会在 HDD 中移动/复制吗?我会说不,其他文档数据应该留在原地,并且更新应该发生在原地(相同的内存位置),但是嗯..不确定了..
更新简单字段与从数组字段中添加或删除子文档之间有区别吗?
我的意思是 - 这个数组操作在某种意义上是特殊的?并触发 HDD 上的文档副本,但简单字段和嵌套对象不会?
如何通过将包含它的字段设置为null 来删除整个大型嵌套对象?这会触发硬盘复制吗?或者不会 - 因为该空间是由于模式的定义而预先分配的......?!
我很困惑。我的项目需要每秒 500 次写入,我正在尝试检测此实现方面是否会影响我。谢谢:)
【问题讨论】:
-
您所讨论的许多行为都与 MMAPv1 存储引擎特别相关,这是 MongoDB 3.0 之前的默认设置。 MongoDB 3.2 以后默认使用 WiredTiger 存储引擎 (docs.mongodb.com/manual/core/wiredtiger),它在管理磁盘上的数据方面具有完全不同的行为。 MMAPv1 在 MongoDB 4.0 (docs.mongodb.com/manual/release-notes/4.0/#deprecate-mmapv1) 中也已弃用。
标签: mongodb database-design nosql database-performance