【问题标题】:SQL Table linking... is it better to have a linking table, or a delimited column?SQL 表链接...最好有一个链接表,还是一个分隔列?
【发布时间】:2011-01-07 19:10:58
【问题描述】:

我的数据库有两个表,一个包含用户列表,另一个包含角色列表。每个用户将属于一个或多个角色,当然每个角色将有多个用户。

我遇到了两种链接信息的方法。第一个是添加第三个表,其中包含两个表中的 ID。然后,一个简单的联接将返回属于某个角色的所有用户,或该用户所属的所有角色。但是,随着数据库的增长,这些简单查询返回的数据集将呈指数级增长。

第二种方法是向用户表中添加一列,其中存储了分隔的角色列表。这将消除对第三个链接表的需要,这可能对数据库增长产生积极影响。缺点是 SQL 没有使用分隔列表的能力。我发现处理该信息的唯一方法是使用临时表和自定义函数。

正在查看我的执行计划,“表扫描”事件是占用资源最多的事件。从等式中删除表格会加快速度,这是有道理的。该函数占用不到1%的资源。

这些测试是在少于 20 条记录的数据库上完成的。随着数据库大小的增长,表扫描将花费更长的时间,因此限制它们可能是最好的选择。

如果使用分隔列表是一种好方法,为什么没有人这样做?

请告诉我您喜欢哪种方法(即使它与我的两种不同)以及原因。

谢谢。

【问题讨论】:

  • 如果您希望存储大量数据,切勿测试少量数据。在少量数据上运行良好的查询通常是在大型数据集上的狗。你得到表扫描的原因可能是你只有 20 条记录,数据库不倾向于使用索引,即使它们存在于一个很小的表中。
  • 您说:“但是,随着数据库的增长,这些简单查询返回的数据集将呈指数级增长。”我无法想象这句话怎么可能是真的,即使你有和用户一样多的角色。用户所属角色的查询受用户数量限制;对于具有角色的用户,反之亦然。叉积查询将是您的数据集平方:多项式增长,而不是指数增长。

标签: sql database tsql database-design


【解决方案1】:

如果您有一个分隔列表,则查找具有给定角色的用户将变得非常昂贵:实际上,您需要对该表进行全面扫描,并查看每一行中该列的所有值,尝试查看它是否包含给定的角色。

单独的表(规范化,多对多关系)是可行的方法,并且通过适当的索引,您将不会发生完全扫描。

例如:

User:  UserId, Name, ....
Role:  RoleId, Name, ....
UserRole:  UserRoleId, UserId, RoleId

(UserRoleId 是可选的,您也可以将 PK 设置为 UserId+RoleId,我不会在这里讨论代理键与复合键)

您需要 (UserId, RoleId) 上的索引是唯一的,以强制不重复。这也将有助于您尝试查看特定用户是否具有特定角色的任何查询(WHERE userId = x AND roleId = y)

如果您要查找用户拥有的所有角色,您将需要仅针对 UserId 的索引。

相反,如果您要查找给定角色拥有的所有用户,则仅在 roleId 上建立索引会加快速度。如果您不执行此查询,或者很少执行此查询,那么没有此索引将稍微加快插入/更新的性能,因为它是少做的一件事。这就是数据库调优这一谨慎的平衡行为。

【讨论】:

    【解决方案2】:
    1. 表扫描意味着您没有任何索引,或者您的查询不允许使用它们。在安全数据库中,您应该很少下载完整的用户/角色列表,除非这是用于管理应用程序。您需要在设计中解决这个问题。

    2. 分隔列表违反第一范式 (1NF) 并且几乎总是会导致长期问题。如果要检索特定角色的所有用户会发生什么?您如何编写该查询?不要走这条路。规范化它。

    3. 如果您使用正确的列类型(即不是到处都是 varchar(4000)varchar(max)),磁盘空间真的不应该成为问题。是的,它会“呈指数级”增长——那又怎样?数据库擅长这种扩展。除非您尝试在 10 gig 硬盘上运行它,否则无需担心。如果您正在尝试在 10 gig 硬盘上运行它,那么您可能需要担心更大的问题。

    简答:不要使用分隔列表。标准化。

    【讨论】:

    • 为你点赞。分隔列表几乎总是不好的,除非您永远不想检索该数据的单个片段(非常罕见的情况)。
    【解决方案3】:

    第一个选项。它被称为多对多连接表。如果您创建适当的索引,这将执行得很好。

    不要使用第二个“非规范化”选项。

    【讨论】:

      【解决方案4】:

      您可以使用单独的桌子,也可以用凿子回到洞穴人那里。选择权在你。

      【讨论】:

      • 他没有提到他的托管计划按每桌收费。
      • @HLGEM:你(和我一样)想象他们在服务器机房里拿着大块石头站着,看起来很无聊?
      • 几乎是的,虽然我的服务器机房是一个真正的洞穴。
      【解决方案5】:

      一个单独的表是要走的路,否则你会试图绕过你的数据库引擎。一个单独的表被适当地规范化——一般来说,随着应用程序的扩展,它被规范化得越好,你会发现它越容易使用。上面greg说的也完全正确。

      【讨论】:

        【解决方案6】:

        虽然我强烈推荐大家都建议的标准化方法。我确实相信拥有一个基于枚举的角色系统可以让您在“角色”列中使用一个数字,并让您避免创建另一个表。

        【讨论】:

        • 嘿,@Eudaimonia!谢谢回复!发布问题7年后。我什至不再为那家公司工作了 :) 虽然这当然是一个可行的选择,但它要求角色是固定的。虽然这可能适用于某些情况,但可能不适用于许多其他情况。在这个问题的特定背景下,这不是一个可行的答案。
        • @RichieACC 哈哈,我想我有回应的冲动。感谢您对答案的反馈!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-23
        相关资源
        最近更新 更多