2009-11-16 40 views
13

每次我看到大约多租户数据库模型的教程告诉你把TenantID在每一个表:Multitenant DB:为什么要在每个表中放置一个TenantID列?

zoos 
------- 
id 
zoo_name 
tenant_id 

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

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

你是否为每个表添加tenant_id以防止连接过度疯狂?它是防范错误的保护措施吗?性能考虑?

+1

设计多租户数据库时有一些注意事项,请阅读MSDN文章:[多租户数据架构](http://msdn.microsoft.com/en-us/library/aa479086.aspx)总之,有几个方法,它是选择和后果的连续体。根据需求做出明智的决定。 – 2012-01-11 09:47:32

回答

8

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

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

首先想到的是查找animals > zoos > tenants比简单animals > tenants要慢。最有可能的是这是一个查找,你会做往往(例如,“让所有的动物为某个租户,无论动物园”)。

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

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

+1

-1。只在动物园表中存储租户ID不是“更规范化”。将它作为外键存储在每个表格中并非无关紧要;这就是你认为用外键做的事情。 – 2012-01-11 13:03:24

+0

是的。数据库越规范化,冗余就越少。我认为你会同意在多个地方存储一个id是冗余的。我从来没有说过这些字段是处理数据一致性的一流外键,但即使它们会由于额外的检查而降低性能。问题在于解释为什么该字段被添加到多个表格中的原因,我认为我这样做了。所以我会说你的-1是没有根据的。 – Blixt 2012-01-11 16:36:50

+1

外键不是多余的。它们是关系模型的核心和显着特征。在多租户共享架构体系结构中,所有外键都是由tenant_id加上其他内容组成的复合键。该租户ID是区分一个租户的行与其他每个租户的行的唯一区别。将租户ID保留在表中,并且还必须禁止插入,更新和删除操作。 (考虑一下。) – 2012-01-13 03:06:12

8

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

所以在现实世界中有一个妥协 - 问题就变成了什么地方,到了什么程度。

请参阅本文Maybe Normalizing Isn't Normal - 和它的结论:

正如老话 推移,正常化,直到它伤害, 非规范化直到它的工作原理

来开始探索这个问题的地方

+0

冒着发生书呆子宗教战争的危险,我不禁想知道这是不是一个自然钥匙是有用的例子适合。如果您的多租户应用是按域名分区的,并且您将tenant_id设置为域名,那么您也可以减少连接。 – Paul 2010-03-17 19:14:02

+0

它不会减少连接 - 你仍然有问题要么包括在多个层次(理论上是坏的)或复杂的连接(还有理论上的糟糕),并且无论自然键总是回来并咬你( - : – Murph 2010-03-18 09:27:33

+1

- 1.如果您规范化了一个多租户,与3NF或5NF的共享关系,那么您将在每个表中获得租户标识符 – 2012-01-11 13:07:08

14

如果您的关键设计考虑因素之一是安全性 - 具体来说,一个客户端在访问另一个客户端的数据时无法完成,关于如何实施此安全性,可能需要在每个表格中添加符合条件的列。描述here的这种策略需要在每张桌子上建立一个视图;假设每个表都包含一个tenantId列,那么如果配置得当,每个视图都可以包含一个“WHERE tenantId = SUSER_SID()”子句(当然,您还需要配置数据库,以便客户端只能访问视图)。

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

但一如既往,涉及到很多“依赖”。如果没有明确的需求,未来需求的可能性很低,然后将该列标准化。只要认识到它比概念或逻辑数据库设计更像是物理实现的设计。

0

那么,Bob可能在动物园No1拥有一只长颈鹿,而乔可能在同一个动物园拥有一只狮子。 他们不应该看对方的数据。

0

N1是为了安全。

在多租户应用程序中,安全性需要是一个强大的概念。

假设您给予用户修改动物的能力。 您可以创建一个表单,显示当前租户的动物园。 如果用户破解表单并传递另一个租户的动物园标识,会发生什么情况?

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

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

+0

您可以在服务器端进行检查以确保用户拥有该ID的权限。不管数据库设计如何,你都需要这样做,但我明白你的意思。 – 2010-11-12 19:27:21

+2

如果用户侵入表单并提供属于另一个租户的动物的id,会发生什么情况?如果用户侵入“我的个人档案“页面提供超级管理员帐户的ID?您完全不能相信用户的输入 - 这适用于任何用户拥有不同权限的系统,而不仅仅是多租户。 – 2012-12-03 19:15:57

相关问题