多租户数据库:为什么在每个表中都放置一个TenantID列?

Mik*_*ler 14 database-design multi-tenant

我见过的关于Multitenant数据库模型的每个教程都告诉您将TenantID放在每个表中:

zoos
-------
id
zoo_name
tenant_id

animals
-------
id
zoo_id
animal_name
tenant_id
Run Code Online (Sandbox Code Playgroud)

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

你是否tenant_id只是为了防止连接过于疯狂而添加到每个表中?它是防范错误的安全措施吗?性能考虑?

Phi*_*ley 14

如果您的一个关键设计考虑因素是安全性 - 具体而言,一个客户端在访问另一个客户端的数据时绝不可能没有 - 那么,根据您实现此安全性的方式,可能需要在每个表中坚持该限定列.这里描述的一种策略要求在每张桌子上建立一个视图; 假设每个表都包含一个tenantId列,那么如果配置正确,每个视图可以包含一个"WHERE tenantId = SUSER_SID()"子句(当然,您配置数据库以便客户端只能访问这些视图).

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

但与以往一样,涉及到很多"它依赖".如果没有明确和现在的需求,并且将来需要的可能性很小,那么将该列标准化.只是意识到它更多地是物理实现的设计,而不是概念或逻辑数据库设计.


Mur*_*rph 9

它的便利性和性能 - 在标准化方面你是绝对正确的,它只需要进入顶部.然后问题变成了获取一些数据(比如动物园 - >动物 - >食物 - >供应商)你必须在理论上非常简单的查询上有非常复杂的连接.

因此,在现实世界中,人们必须妥协 - 然后问题就变成了地点和程度.

看到这篇文章也许正常化不正常 - 及其结论:

正如古老的谚语所说的那样,规范化直到它受到伤害,反规范化直到它起作用

作为一个开始探索这个主题的地方


小智 8

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

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


Bli*_*ixt 5

首先想到的是,它animals > zoos > tenants比简单的查找起来要慢animals > tenants.而且很可能这是您经常进行的查询(例如,"为某个租户获取所有动物,无论动物园").

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

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

  • 我认为这里只是一个语言问题。任何可以推断的值都是“冗余”数据,也称为“非规范化”数据。通常出于性能原因保留它。在这种情况下,“tenant_id”是*非规范化*或*冗余*,因为它存储了两次,如果您不小心更改了其中一个而不更改另一个,就会发生数据不一致/损坏。完全规范化的数据库不允许这样做。请阅读:https://en.wikipedia.org/wiki/Database_normalization (2认同)