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

时间:2010-03-26 00:01:13

标签: sql mysql normalization

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

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

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

谢谢!

5 个答案:

答案 0 :(得分:3)

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

users
    id
    name

phonenumbers
    user_id
    phonenumber

所以,是的,这是完全合理的。

答案 1 :(得分:1)

normalize在多大程度上可能是一个艰难的决定。关于此主题(Database Development Mistakes Made by App Developers)的最佳StackOverflow答案之一警告(1)未能正常化,以及(2)过度规范化。

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

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

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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

这是多租户数据库中的设计决策。使用“root”表,显然你拥有来拥有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,它应该是表中的第一列,在大多数索引中,并且在大多数情况下应该是主键的一部分,除非另有说明。在可能的情况下,它应该是大多数存储过程中的必需参数。

答案 4 :(得分:0)

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