来自 电脑系统 2019-10-04 14:44 的文章
当前位置: 金沙澳门官网网址 > 电脑系统 > 正文

每一天一译,MongoDB数据库设计中6条第一的经验法

原文:6 Rules of Thumb for MongoDB Schema Design: Part 3

原文:6 Rules of Thumb for MongoDB Schema Design: Part 2

By William Zola, Lead Technical Support Engineer at MongoDB

By William Zola, Lead Technical Support Engineer at MongoDB

这篇文章是系列的最后一篇。在第一篇文章里,我介绍了三种针对“一对多 ”关系建模的基础方案。在第二篇文章中,我介绍了对基础方案的扩展:双向关联和反范式化。

在上一篇文章中我介绍了三种基本的设计方案:内嵌,子引用,父引用,同时说明了在选择方案时需要考虑的两个关键因素。

反范式可以让你避免一些应用层级别的join,但是这也会让更新变的更复杂,开销更大。不过冗余那些读取频率远远大于更新频率的字段还是值得的。

一对多中的多是否需要一个单独的实体。

如果你还没有读过前两篇文章,欢迎一览。

这个关系中集合的规模是一对很少,很多,还是非常多。

让我们回顾下这些方案

在掌握了以上基础技术后,我将会介绍更为高级的主题:双向关联和反范式化。

你可以采取内嵌,或者建立one端或者N端的引用,也可以三者兼而有之。

双向关联

你可以在one端或者N端冗余多个字段

如果你想让你的设计更酷,你可以让引用的“one”端和“many”端同时保存对方的引用。

下面这些是你需要谨记的:

以上一篇文章讨论过的任务跟踪系统为例。有person和task两个集合,one-to-n的关系是从person端到task端。在需要获取person所有的task这个场景下需要在person这个对象中保存有task的id数组,如下面代码所示。

1、优先考虑内嵌,除非有什么迫不得已的原因。

图片 1

2、需要单独访问一个对象,那这个对象就不适合被内嵌到其他对象中。

在某些场景中这个应用需要显示任务的列表(例如显示一个多人协作项目中所有的任务),为了能够快速的获取某个用户负责的项目可以在task对象中嵌入附加的person引用关系。

3、数组不应该无限制增长。如果many端有数百个文档对象就不要去内嵌他们可以采用引用ObjectID的方案;如果有数千个文档对象,那么就不要内嵌ObjectID的数组。该采取哪些方案取决于数组的大小。

图片 2

4、不要害怕应用层级别的join:如果索引建的正确并且通过投影条件限制返回的结果,那么应用层级别的join并不会比关系数据库中join开销大多少。

这个方案具有所有的一对多方案的优缺点,但是通过添加附加的引用关系。在task文档对象中添加额外的“owner”引用可以很快的找到某个task的所有者,但是如果想将一个task分配给其他person就需要更新引用中的person和task这两个对象(熟悉关系数据库的童鞋会发现这样就没法保证操作的原子性。当然,这对任务跟踪系统来说并没有什么问题,但是你必须考虑你的用例是否能够容忍)

5、在进行反范式设计时请先确认读写比。一个几乎不更改只是读取的字段才适合冗余到其他对象中。

在一对多关系中应用反范式

6、在mongodb中如何对你的数据建模,取决于你的应用程序如何去访问它们。数据的结构要去适应你的程序的读写场景。

在你的设计中加入反范式,可以使你避免应用层级别的join读取,当然,代价是这也会让你在更新是需要操作更多数据。下面我会举个例子来进行说明

设计指南

反范式Many -> One

当你在MongoDB中对“一对多”关系进行建模,你有很多的方案可供选择,所以你必须很谨慎的去考虑数据的结构。下面这些问题是你必须认真思考的:

以产品和零件为例,你可以在parts数组中冗余存储零件的名字。以下是没有加入反范式设计的结构。

关系中集合的规模有多大:是一对很少,很多,还是非常多?

图片 3

对于一对多中”多“的那一端,是否需要单独的访问它们,还是说它们只会在父对象的上下文中被访问。

反范式化意味着你不需要执行一个应用层级别的join去显示一个产品所有的零件名字,当然如果你同时还需要其他零件信息那这个应用层的join是避免不了的。

被冗余的字段的读写的比例是多少?

图片 4

数据建模设计指南

在使得获取零件名字简单的同时,执行一个应用层级别的join会和之前的代码有些区别,具体如下:

在一对很少的情况下,你可以在父文档中内嵌数组。

图片 5

在一对很多或者需要单独访问“N”端的数据时,你可以采用数组引用ObjectID的方式。如果可以加速你的访问也可以在“N”端使用父引用。

反范式化在节省你读的代价的同时会带来更新的代价:如果你将零件的名字冗余到产品的文档对象中,那么你想更改某个零件的名字你就必须同时更新所有包含这个零件的产品对象。

在一对非常多的情况下,可以在“N”端使用父引用。

在一个读比写频率高的多的系统里,反范式是有使用的意义的。如果你很经常的需要高效的读取冗余的数据,但是几乎不去变更他d话,那么付出更新上的代价还是值得的。更新的频率越高,这种设计方案的带来的好处越少。

如果你打算在你的设计中引入冗余等反范式设计,那么你必须确保那些冗余的数据读取的频率远远大于更新的频率。而且你也不需要很强的一致性。因为反范式化的设计会让你在更新冗余字段时付出一定的代价

例如:假设零件的名字变化的频率很低,但是零件的库存变化很频繁,那么你可以冗余零件的名字到产品对象中,但是别冗余零件的库存。

相关文章:

需要注意的是,一旦你冗余了一个字段,那么对于这个字段的更新将不在是原子的。和上面双向引用的例子一样,如果你在零件对象中更新了零件的名字,那么更新产品对象中保存的名字字段前将会存在短时间的不一致。

MongoDB数据库设计中6条重要的经验法则,part 1(每日一译:2014-07-23)

反范式One -> Many

MongoDB数据库设计中6条重要的经验法则,part 2(每日一译:2014-07-24)

你也可以冗余one端的数据到many端:

本文由金沙澳门官网网址发布于电脑系统,转载请注明出处:每一天一译,MongoDB数据库设计中6条第一的经验法

关键词: