我应该在多个表中包含 user_id 吗?

Posted

技术标签:

【中文标题】我应该在多个表中包含 user_id 吗?【英文标题】:Should I include user_id in multiple tables? 【发布时间】:2011-01-31 23:53:19 【问题描述】:

我正处于多用户应用程序的规划阶段,每个用户只能访问自己的数据。会有一些相互关联的表,所以我可以使用 JOIN 来确保他们只访问他们的数据,但是我应该在每个表中包含 user_id 吗?这会更快吗?从长远来看,这肯定会使一些查询变得更容易。

具体来说,问题是关于包含 user_id 字段的多个表。

例如,每个用户都可以针对这些项目配置类别、项目(在这些类别中)和子项目。从用户到通过其他表的子项目有一条逻辑路径,但它需要 3 个 JOIN。我应该在所有表中都包含 user_id 吗?

谢谢!

【问题讨论】:

【参考方案1】:

这是多租户数据库中的设计决策。对于“根”表,显然您必须拥有 user_id。但是在非“根”表中,您可以在使用代理 PK 时进行选择。

假设您有项目的用户和操作的项目。项目显然必须有一个 user_id,但如果操作与一个且仅一个项目相关联,那么 user_id 是多余的,并且也违反了正常形式,因为如果它要移动到另一个用户的项目(在您的用例中可能不太可能) ),项目 FK 和用户 FK 都必须更新。通常在多租户场景中,这实际上是不可能的场景,因此每个表的主键实际上是租户和租户“内部”的唯一主键的组合(也可能恰好是全局唯一的) .

如果您在设计中广泛使用自然键,那么显然租户+自然键是必要的,以便可以使用每个租户的自然键。只有在使用 IDENTITY 或 GUID 或序列之类的代理项时,这才会成为一个问题,因为将 IDENTITY 设为 PK 是很有诱惑力的,毕竟它在定义上是唯一的。

在所有表中都有 user_id 确实允许您在视图中执行某些操作以增强安全性(深度防御),为您提供一点防御性编程(在 SQL Server 中,您可以通过内联表值函数限制所有访问 -本质上是参数化的视图——它要求应用程序在每个“表”访问中指定 user_id),并且还允许您通过叉车共享键上的所有内容轻松扩展到多个数据库。

请参阅 this article 了解一些有趣的见解。

(在像 Teradata 这样的大规模多并行范例中,PRIMARY INDEX 确定数据所在的放大器,因此我认为这是停止将行重新分配到其他放大器的必要条件。)

一般来说,我会说您在每个表中都有一个tenantid,它应该是表中的第一列,在大多数索引中,并且在大多数情况下应该是主键的一部分,除非另有说明。在可能的情况下,它应该是大多数存储过程中的必需参数。

【讨论】:

【参考方案2】:

通常,您使用外键来关联表之间的数据。在许多情况下,这个外键就是用户 ID。例如:

users
    id
    name

phonenumbers
    user_id
    phonenumber

所以是的,这很有意义。

【讨论】:

我的问题是是否包含多个表,而不仅仅是一个,我将编辑我的问题。【参考方案3】:

如果一个类别只能属于一个用户,那么可以,您需要在类别表中包含 user_id。如果一个类别可以属于多个人,那么您将有一个将类别 ID 映射到用户 ID 的单独表。如果两者之间存在一对一映射,您仍然可以这样做,但没有真正的理由。

如果您可以保证始终通过加入类别表来访问这些子表,则无需在其他表中包含 user_id。如果您有机会独立于类别表访问它们,那么您还应该在这些表上拥有 user_id。

【讨论】:

【参考方案4】:

normalize 的范围可能是一个艰难的决定。关于此主题的最佳 *** 答案之一 (Database Development Mistakes Made by App Developers) 警告 (1) 未能规范化和 (2) 过度规范化。

您提到“从长远来看”在多个表中重复相同的数据可能更容易(也就是说,不规范化该数据)。查看上一个链接中的“不通过视图简化复杂查询”主题。如果您有效地使用视图,则在编写视图时只需执行一次 3 连接查询,然后您就可以在大多数情况下使用没有连接的查询。

大多数开发人员倾向于不规范化,因为它看起来更简单。继续并正常化。使用视图来简化您的日常查询。当您的需求变得更复杂或您决定添加功能时,您会很高兴您将时间投入到关系数据库设计中。

或者,根据您的工具集,您可能希望使用database abstraction 层,该层在您操作更高级别的数据对象时在幕后进行关系设计。

【讨论】:

【参考方案5】:

如果是 Oracle,那么您可能会设置一个细粒度的安全规则来执行连接并根据原始用户 ID 的存在来阻止某些活动......(SELECT INSERT UPDATE DELETE 等) 您需要登录用户和 user_id 之间的映射。您可以使用 uid,但请记住,如果在某些灾难后重建数据库,此数字可能会发生变化...

【讨论】:

以上是关于我应该在多个表中包含 user_id 吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 Postgres 的单个索引中包含多个列

更新两个表中的数据。一种在一列中包含多个数据

如何确保仅从特定表中选择第一条记录,该表可以在 DB2 中包含多个相同 ID 的记录

如何编写一个查询以从SQL Server中包含类似名称的多个表中获取数据

使用多个单元格从另一张纸中搜索数据吗?

Android中包含多个可拖动列表的水平滚动