【问题标题】:MySQL Question - How to handle multiple types of users - one table or multiple?MySQL 问题 - 如何处理多种类型的用户 - 一张或多张?
【发布时间】:2009-06-28 02:21:07
【问题描述】:

我正在为一个拥有多种“类型”用户的组织设计一个数据库。起初,我只创建了一个用户表。然而,虽然所有用户共享一些公共信息(名字、姓氏、用户名、密码等),但每种用户类型都需要一个或两个附加字段,这些字段并不适用于所有用户。虽然我可以创建这些额外的字段并将它们设置为 NULL,但我不希望这样做,因为这些字段是外键,它给我带来了问题。

这种情况通常如何处理?

谢谢!

【问题讨论】:

    标签: sql mysql database


    【解决方案1】:

    这是著名的标准化问题。

    查看本文或其他类似文章,尝试找到适合业务需求的答案。

    To normalize or not to normalize

    【讨论】:

    • 非常感谢这篇文章,发现它很有帮助。我有很多关于这个话题的问题,这回答了很多问题。谢谢!
    • 打算给 +1,但链接不再有效。请问您要更新吗?
    • @Gabriel Wow - 我不知道它是否有效。我已将其更新为正确的文章
    【解决方案2】:

    您不创建包含大量 NULL 的大表的直觉是正确的。从存储/检索/维护的角度来看,以及从数据验证的角度来看(稍后会详细介绍),这是个坏主意。

    两种最常见的方法:

    1) 有一个包含所有公共字段的用户表,包括一个“userType”字段。然后为每个包含额外字段的用户类型创建一个单独的表。所有用户在用户表和一个或多个特定用户类型表中都有一行。这对于存储和快速登录来说是最规范和最有效的。这还允许您使用约束和外键来确保每种用户类型的所有必需信息都可用。

    2) 有一个包含所有公共字段的用户表。有另一个名为 UserAttributes 的表,其中包含用户 ID、键和值的字段。特定用户的任何额外元数据都可以存储在此处。这样做的好处是不需要任何数据库管理来添加新的用户类型或要为每个用户类型存储的元数据。但是,它不允许您在数据库级别进行任何数据验证。

    【讨论】:

    • 谢谢,dj_segfault。我选择了您的选项#1,并创建了一个包含公共字段的用户表和一个由其他更“特定”用户表引用的 userType 字段。 NULLS 肯定会引起头痛,我很高兴现在摆脱它们!
    • 如果我错了,请纠正我(这种情况经常发生),但如果有人以这样一种方式存储他们的数据,即常用字段处于“用户”级别,如 fname、lname、电子邮件, pw...等等。没有办法通过一个查询获得更多用户特定的信息,对吧?总是需要根据用户类型进行第二次查询才能获得更具体的信息。
    • @ackerchez 当然有。要获取所有信息,您所要做的就是通过您的 UID 将所有特定于用户类型的用户表与主用户表进行内部连接。不属于该用户类型的表的列将为空。
    【解决方案3】:

    因此,关系模型不支持“继承”,这可能有助于解决这个问题(尽管一些数据库引擎,例如 PostgreSQL,确实支持继承)。

    所以,我首先要问自己——至少在某些情况下,不同类型的用户是否需要能够出现在相同的上下文中?如果是这样,那么您不能只是将“共同的列”复制并粘贴到多个表中(至少在不损害在这些情况下可以通过外键对单个表进行的完整性检查的情况下)。

    第二个问题——一个用户曾经有可能担任多个角色吗?在许多情况下,这将是不寻常,但并非完全不可能,例如员工也可能是供应商或客户。

    如果我无法对这些指示我的问题给出明确的答案,我会设置一个只有公共字段的用户表;并为供应商、员工、beta 测试人员、客户以及我可能为用户提供的任何其他类型和角色提供单独的表,每个表都有自己的专用列以及用户表上的外键以获取其余部分。

    我意识到规范化模式现在已经过时了,但几十年来它们一直忠实地为我服务,我非常喜欢它们——我只在需要特定优化时才去规范化,而且这种情况很少发生想想!-)。

    在这里可能有用的一种非规范化是用户表中的枚举列,指示每个特定用途的“主要”或“唯一”角色(如果我是足够急于从一开始就拥有它......;-)......但如果某些特定查询的性能需要它作为特定优化,我可能会等待添加它,而不是从开始(请注意,这是永远不要在查询中使用SELECT * FROM 的关键原因——如果您稍后使用ALTER TABLE 添加一列,那么SELECT * 就是会中断的那一位!-)。

    【讨论】:

    • Alex,非常感谢您的回复,这对我很有帮助。我按照您的建议做了,并为每个用户类型设置了一个包含常用字段的表,以及为其他不常用字段设置的单独表。我也在用户表中添加了一个角色枚举列。谢谢!
    【解决方案4】:

    你没有说你是否使用高级语言,所以我只是举一个类似 DB 的例子:

    数据库设计很难。因此,这将是一个快速而简单的答案。

    您的问题是关于数据关系和数据库设计的基本问题。搜索一些基本的操作指南来帮助回答这个问题。考虑如何对您的信息进行分组,并从其他集合(表)“返回”到主集合(表)可能会有所帮助。

    所以,用户就是用户——这就是你的桌子。它应该包含与用户相关的主要、常见的数据元素(列)。

    那么,这另一组信息(例如,权限或其他东西)是另一个表。

    只要确保这个其他表有一个值(列)指向它所引用的用户。您可能希望告诉您的数据库在它们之间创建一个“索引”(以提高查找性能等)

    例如,一种用户的“权限”表:

      - integer "id"        <--- unique, index column, auto-increment
      - integer "user_id"   <--- this is which user this belongs
      - ...
      - Boolean "can_write"         <--- example data column
      - Boolean "can_read"          <--- example data column
      - Boolean "can_reboot_system" <--- example data column
      - etc, whatever you want
    

    因此,您可以“SELECT * FROM user_table WHERE first_name = 'joe' (or such) ... 来获取用户。在那里,我希望您有某种 'id' 值来识别该行.

    现在,只需执行 'SELECT * FROM permissions WHERE user_id = 'nnnn' (无论该用户的 id 是什么)。

    如果用户只有 1 个权限集,那么您可以只拥有该 user_id 而无需额外的“id”列。

    【讨论】:

    • joej- 我从来没有想过在数据库级别表达权限。当然,这似乎是个好主意。现在,我只有一个引用用户的“角色”表(然后我使用 php 代码强制执行该角色)。不过我喜欢你的想法,我打算更多地使用它。谢谢!
    猜你喜欢
    • 2018-08-05
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-04
    相关资源
    最近更新 更多