20

我看到的关于多租户数据库模型的每个教程都告诉您将 TenantID 放在每个表中:

zoos
-------
id
zoo_name
tenant_id

animals
-------
id
zoo_id
animal_name
tenant_id

但是,这对我来说似乎是多余的。为什么不将tenant_id列添加到表中并利用和zoos之间的外键关系?zoosanimals

您是否添加tenant_id到每个表只是为了防止连接变得太疯狂?它是针对错误的保护措施吗?性能考虑?

4

6 回答 6

15

如果您的关键设计考虑因素之一是安全性——具体来说,一个客户端在访问另一个客户端的数据时不可能不怎么不——那么,根据您实现此安全性的方式,可能需要在每个表中粘贴该限定列。这里描述的一种策略需要在每个表上建立一个视图;假设每个表都包含一个tenantId 列,那么如果正确配置每个视图都可以包含一个“WHERE tenantId = SUSER_SID()”子句(当然,您配置数据库以便客户端只能访问视图)。

另一个因素(如我目前的工作)是加载仓库数据(ETL)。表在tenantId 上进行分区(我们使用表分区,但分区视图也可以),并且可以轻松地为客户端加载或卸载数据,而不会严重影响任何其他客户端。

但与以往一样,涉及很多“取决于”。如果没有明确的当前需求,并且未来需求的可能性非常低,则将该列标准化。只要意识到它更多的是物理实现的设计,而不是概念或逻辑数据库设计。

于 2009-11-16T15:36:41.157 回答
10

它在那里是为了方便和性能 - 就标准化而言,你是绝对正确的,它只需要进入顶部。那么问题就变成了要获取一些数据(比如动物园 -> 动物 -> 食物 -> 供应商),您必须对那些名义上非常简单的查询进行非常复杂的连接。

因此,在现实世界中,人们必须妥协——然后问题就变成了在哪里以及在什么程度上。

请参阅这篇文章也许规范化不正常- 及其结论:

正如古老的格言所说,规范化直到它受伤,非规范化直到它起作用

作为开始探索该主题的地方

于 2009-11-16T15:14:08.300 回答
9

如果我在层次结构的顶部(即动物园级别)有tenantID,那么您需要考虑几个问题。

  1. 层次结构的顶部永远不会改变,例如,如果您需要在动物园级别上方的树上添加一个节点(例如区域 -> 动物园 -> 动物),那么它将每次都强制重新组织。
  2. 对于某些查询,您将被迫从层次结构的顶部开始,即给我一个所有可用动物的列表将迫使您从树的顶部开始
  3. 为什么不使用模式?每个租户都在他们自己的架构中被隔离。这也将很好地分离数据集。
于 2009-11-16T21:34:59.800 回答
6

首先想到的是,查找animals > zoos > tenants比简单查找要慢animals > tenants。这很可能是您经常进行的查找(例如,“获取某个租户的所有动物,无论动物园如何”)。

对于中小型应用程序,您可以使用更规范的结构,但为了提高效率,您应该使用无关数据(一般来说,多租户应用程序并不小)。只要确保它不会“不同步”,这是冗余数据带来的风险。

回答你的最后一段,原因是性能,纯粹而简单。连接不是坏事;它们可以帮助您将一段数据保存在一个地方而不是三个地方。这绝对不是为了防止错误。将tenant_id字段添加到更多表会增加错误的风险(尽管对于永远不会更改的 id 来说,这不是什么大问题)。

于 2009-11-16T15:13:20.207 回答
0

好吧,鲍勃可能在 1 号动物园拥有一只长颈鹿,而乔可能在同一个动物园拥有一只狮子。他们不应该查看彼此的数据。

于 2009-11-16T16:53:43.827 回答
-1

N1的原因是为了安全。

在多租户应用程序中,安全需要成为一个强有力的概念。

假设您赋予用户修改 Animal 的能力。您创建一个带有选择的表单,显示当前租户的动物园。如果用户破解表单并传递另一个租户的动物园 ID,会发生什么?

动物将被转移到另一个租户的另一个动物园!

这是多租户应用程序中的真正痛苦!

于 2010-11-12T09:57:38.820 回答