【问题标题】:What is the optimal relational database design for storing an unknown number of similar but unique entities存储未知数量的相似但唯一实体的最佳关系数据库设计是什么
【发布时间】:2020-01-28 18:38:31
【问题描述】:

我们正在设计的数据库允许用户通过多个第三方服务进行身份验证,主要是社交媒体(推特、脸书等)。这些服务的数量将不为人知且不断增加。每个服务都需要一组独特的数据进行身份验证,这与其他服务不同。

一个 用户可以验证许多 服务,但他们只能验证每个服务中的一个服务的类型

可能的解决方案:

A) 这个问题最直接的解决方案是简单地为每个服务添加一个列到包含该服务的 JSON 身份验证的 user 表。但是,这违反了规范化,因为在数据库中留下了大量的空值。例如,当有 50 个这样的集成时会发生什么?

B) 每个服务在数据库中都有自己的表。不再需要 JSON,因为可以正确描述每个字段。然后每个服务都需要一个查找表“user_has_service”。这是一个只包含两个外键的表,一个用于用户,一个用于服务,将它们链接在一起。这个选项看起来是最正确的,但是效率非常低,并且会通过许多操作来确定用户拥有哪些服务,并随着服务数量的增加而增加。我相信在这种情况下,查找表的 ID 字段需要是 userservice 的某种哈希值,这样就不可能重复插入。

根本不是数据库专家,我已经为此苦苦挣扎了很长一段时间。有什么想法吗?

【问题讨论】:

  • @philipxy 不,不是。 1) 应查看数据;分析;通过数据分析和关系模型设计,而不是通过 OO 的短视的非数据镜头。 2) 然而,简单来说,OO 继承转换为关系子类型。 3)这个问题与OO继承无关(尽管OO继承或任何其他OO boondogle都可以应用于它),这里没有OO继承。这里的继承(英语、数学、Codd 定义,而不是 OO 定义)在于关系键:参考我的答案。
  • @PerformanceDBA 链接的问题使用“继承”一词,但它及其答案是关于以关系方式处理子类型。 (虽然继承碰巧涉及子类型的特殊情况。)
  • @philipxy。是的,我知道。唯一适用于数据库上下文的 OO 继承类型是子类型,并且在这个问题中不存在。这就是为什么这个 Q 不是那个 Q 的骗子。请再次阅读我的评论。

标签: sql database database-design relational-database database-normalization


【解决方案1】:

A) 最直接的解决方案... JSON

你是对的,选项 A 严重错误。它打破了 Codds 的第一范式,因此它不是关系的。数据库中的 NULL 表示不完整的规范化,这会导致复杂的 SQL 代码。不惜一切代价避免。

相似但独特

需要明确的是,它们是服务独有的,这是真的。 {LoginName; UserName; Email; UserId; etc} 都是相似的,这仅在实现意义上是正确的,而不是在数据中。

我可能需要把它画出来。

这是个好主意。视觉数据模型要有效得多,因为 (a) 大脑比文本更能理解它,并且 (b) 因此可以计算出细节;矛盾;丢失位;等等。视觉上进行每次迭代比使用文本更容易。

其次,我们从 1987 年开始就有可视化建模工具(1984 年用于封闭组),这些工具在 1993 年成为标准。希望您能理解符合标准的模型比本土或公司提供的一种。它显示所有技术细节,而不是一小部分。

这个策略有名字吗

它是普通的旧关系数据建模,其中包括规范化(确保符合 Codd 的范式,而不是疯狂地实施 NF 是碎片化的渐进步骤)。

障碍

需要理解和消除的一个问题是这个。 “理论家”打着“关系”的旗号推销和宣传 1960 年代的档案系统。其特点是每个文件中都有一个Record IDs。该方法确保数据库保持物理而不是逻辑,这正是 Codd 用他的关系模型克服的东西:一个合乎逻辑的数据库,因此任何查询方都非常容易浏览当前的数据库;计划;或计划外。

1960 年代的 RFS 与 1970 年后的关系数据库的本质区别在于:

  • RFS 通过物理指针 (Record ID) 维护文件之间的引用,而关系数据库通过逻辑键维护表之间的引用。
  • 根据 Codd,逻辑键是“由数据组成”
    • (系统制造的数据不是“由数据组成”)
    • (使用 SQL 命令PRIMARY KEY 不会神奇地用关系键的属性和质量来涂抹数据:如果您使用PRIMARY KEY RecordID,则您处于 1960 年的物理范式,而不是 1970 年后的关系范式)
  • Lo​​gical Keys 提供关系完整性(与引用完整性不同,它是 SQL 的一个普通功能),远远优于 1960 年代 RFS 获得的功能
  • 以及卓越的速度和力量(远不如 JOINs 和更小的套装)

关系数据库

因此,根据 Codd,我将以关系数据模型的形式为您提供答案。

  • 关系完整性的一个例子:

    • UserServiceProperty 中的 ServiceProperty FK 元素被限制为 ServiceProperty 中的 PK(特定组合)
    • 带有Facebook.Email 的 UserServiceProperty 行被阻止
    • 基于 1960 年的 RFS 的 Record ID 被“理论家”宣传为“关系型”不能做到这一点,允许出现诸如此类的各种错误。
  • 我所有的数据模型都在 IDEF1X 中呈现,这是自 1993 年以来为关系数据库建模的标准

  • 我的IDEF1X Introduction是初学者的必备读物。

  • IDEF1X Anatomy 是为那些已经失效的人提供的复习。

  • 如果您在直接从数据模型读取 谓词 时遇到问题,请告诉我,我会以文本形式生成它们。

请随时提出问题,越具体越好。

【讨论】:

  • @Ampix0 请评估。
  • 非常感谢您的详细回答和示例。阅读您的示例后,我觉得好像我可能过度考虑了这个问题。我相信这是正确的解决方案。谢谢你说清楚。
  • @Ampix0 1) 不客气。 2)我更正了示例数据中的一个错误,并添加了几句细节。 3) 如果您想了解策略,请阅读我的其他一些答案。
【解决方案2】:

你可以设置:

  • 一个名为services 的引用表列出所有可用的服务,列如service_id(主键)、service_namedescriptions 等。每个服务在此表中表示为一条记录。

  • 名为services_properties 的表用于存储服务的属性;该表有 3 列:service_idservices 的主键的外键)、property_nameproperty_value。可以在 service_id/propery_value 元组上设置唯一约束以避免重复。每个服务在services_properties 表中有几条记录。这种灵活的结构让您可以根据需要为每个服务存储尽可能多的不同属性,而无需为每个服务创建新表

  • 一个名为user_services 的映射表,它将用户与服务相关联。列将是service_iduser_id,作为services 表和users 表的主键的外键。您可以查询此表,轻松列出每个用户订阅的服务。

【讨论】:

  • 我可能需要把它画出来。这似乎有点类似于选项 B,我想我也想出了一些类似的东西。您在“property_name”和“property_value”中的图像是什么?那部分我有点迷失了。
  • @Ampix0:这是不同的。在选项 B 中,每个服务都在自己的表中(这使得以通用方式查询变得困难)。在我的回答中,所有服务都进入同一个表,存储所有服务的属性。
  • 这个策略有名称,所以我可以对此进行更多研究吗?我在这里很近,但缺少一件。我现在明白你的意思是每个服务在服务属性下有多个列表,但我错过了一些东西,这些值然后映射到用户。现在,这些值似乎已映射到服务。我想对此进行更多研究,但不知道该怎么称呼它。
  • @Ampix0:我明白你现在的意思了。为此,您需要在表中再增加一列来存储用户 ID。在这种情况下,映射表 user_services 不是强制性的。
猜你喜欢
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-27
  • 2016-08-09
  • 2010-10-30
相关资源
最近更新 更多