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

时间:2009-11-16 15:07:35

标签: database-design multi-tenant

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

zoos
-------
id
zoo_name
tenant_id

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

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

您是否为每个表添加tenant_id只是为了防止连接过于疯狂?它是防范错误的安全措施吗?绩效考虑?

6 个答案:

答案 0 :(得分:14)

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

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

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

答案 1 :(得分:9)

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

所以在现实世界中,人们不得不妥协 - 然后问题变成了在哪里以及在多大程度上。

请参阅此文Maybe Normalizing Isn't Normal - 及其结论:

  

作为古老的谚语   去,正常直到它疼,   非规范化直到它起作用

作为开始探索主题的地方

答案 2 :(得分:8)

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

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

答案 3 :(得分:5)

首先想到的是,查找animals > zoos > tenants的速度比简单animals > tenants要慢。而且很可能这是一个查找,你会做经常(例如,“为某个租户获取所有动物,不管动物园”)。

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

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

答案 4 :(得分:0)

嗯,鲍勃可能在动物园1号拥有一只长颈鹿,而乔可能在同一个动物园里拥有一头狮子。 他们不应该看对方的数据。

答案 5 :(得分:-1)

N1用于安全的原因。

在多租户应用中,安全性必须是一个强大的概念。

假设您授予用户修改Animal的权限。 您创建一个表单,其中包含向当前租户显示动物园的选项。 如果用户破解表单并传递另一个租户的动物园ID,会发生什么?

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

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