如前所述,没有像 SQL 的第二范式这样的规则。
但是,我将在此处列出与 MongoDB 优化相关的一些最佳实践和常见陷阱。
过度使用嵌入
BSON 限制
与流行的看法相反,引用并没有错。假设您有一个图书馆,并且您想要跟踪租金。你可以从这样的模型开始
{
// We use ISBN for its uniqueness
_id: "9783453031456"
title: "Schismatrix",
author: "Bruce Sterling",
rentals: [
{
name:"Markus Mahlberg,
start:"2015-05-05T03:22:00Z",
due:"2015-05-12T12:00:00Z"
}
]
}
虽然此模型存在几个问题,但最重要的问题并不明显 - 由于 BSON 文档的大小限制为 16MB,因此出租数量有限。
文档迁移问题
将租金存储在数组中的另一个问题是,这会导致相对频繁的文档迁移,这是一项相当昂贵的操作。 BSON 文档永远不会被分区和创建,并在它们增长时预先分配一些额外的空间。这个额外的空间称为填充。当超出填充时,文档将移动到数据文件中的另一个位置并分配新的填充空间。如此频繁地添加数据会导致频繁的文档迁移。
因此,最佳做法是防止频繁更新增加文档的大小并改用引用。
因此,对于示例,我们将更改单个模型并创建第二个模型。一、本书的模型
{
_id: "9783453031456",
title:"Schismatrix",
author: "Bruce Sterling"
}
出租的第二个模型如下所示
{
_id: new ObjectId(),
book: "9783453031456",
rentee: "Markus Mahlberg",
start: ISODate("2015-05-05T03:22:00Z"),
due: ISODate("2015-05-05T12:00:00Z"),
returned: ISODate("2015-05-05T11:59:59.999Z")
}
作者或承租人当然可以使用相同的方法。
过度标准化的问题
让我们回顾一下。开发人员将识别业务案例中涉及的实体,定义它们的属性和关系,编写相应的实体类,用头撞墙几个小时,以使三重内部-外部-高于和超越 JOIN 工作所需对于用例,所有人从此过上幸福的生活。那么为什么要普遍使用 NoSQL 而特别是 MongoDB 呢?因为没有人从此过上幸福的生活。这种方法扩展得非常可怕,几乎唯一的扩展方法是垂直的。
但 NoSQL 的主要区别在于,您可以根据需要回答的问题对数据进行建模。
话虽如此,让我们看一个典型的 n:m 关系,并以作者与书籍的关系为例。在 SQL 中,您将有 3 个表:两个用于您的实体(books 和 authors),一个用于关系(谁是哪本书的作者? )。当然,您可以使用这些表并创建它们的等效集合。但是,由于 MongoDB 中没有 JOIN,因此您需要三个查询(一个用于第一个实体,一个用于其关系,一个用于相关实体)来查找实体的相关文档。这是没有意义的,因为 n:m 关系的三表方法是专门为克服 SQL 数据库强制执行的严格模式而发明的。
由于 MongoDB 有一个灵活的模式,第一个问题是在哪里存储关系,记住过度使用嵌入引起的问题。由于作者在未来几年可能会写很多书,但一本书的作者身份很少(如果有的话)改变,答案很简单:我们将作者作为对作者的参考存储在书籍数据中
{
_id: "9783453526723",
title: "The Difference Engine",
authors: ["idOfBruceSterling","idOfWilliamGibson"]
}
现在我们可以通过两个查询找到该书的作者:
var book = db.books.findOne({title:"The Difference Engine"})
var authors = db.authors.find({_id: {$in: book.authors})
我希望以上内容可以帮助您决定何时真正“拆分”您的收藏并避开最常见的陷阱。
结论
关于你的问题,这是我的答案
- 如前所述:否,但牢记技术限制应该会让您知道何时可行。
-
还不错——只要它适合您的用例。如果您有给定的类别及其
_id,则很容易找到相关产品。加载产品时,您可以轻松获取产品所属的类别,甚至效率更高,因为默认情况下会为 _id 编制索引。
- 我还没有找到使用 MongoDB 无法完成的用例,尽管使用 MongoDB 可能会有些复杂。恕我直言,你应该做的是总结你的功能和非功能需求,并检查优点是否大于缺点。我的经验法则:如果您的需求列表中有“可扩展性”或“高可用性/自动故障转移”之一,那么 MongoDB 值得一看。