AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 314788
Accepted
Stonecraft
Stonecraft
Asked: 2022-07-25 10:43:14 +0800 CST2022-07-25 10:43:14 +0800 CST 2022-07-25 10:43:14 +0800 CST

如何使用自然键和代理键获得“两全其美”?DBMS 会更好吗?

  • 772

我正在设计我的第一个数据库,我发现自己对在为分类变量的每个实例存储整数或字符串之间进行选择感到沮丧。

我的理解是,如果我有一个包含城市的表,我想将其作为国家表的子项,那么最有效的方法是将国家表的 PK 作为城市表中的 FK。但是,为了便于使用和调试,最好始终将字符串名称与国家/地区 PK 相关联。我考虑过的每个解决方案要么不被推荐,要么看起来过于复杂。

我想就这些方法的优点发表意见(或了解新方法),并了解是否必须采用这种方式,或者数据库是否只是因为传统而采用这种方式。

可能的方法:

  1. 使用字符串作为国家/地区的 PK。然后我将在任何子表中为它提供一个人类可读的 FK。显然性能不如使用整数,但我怀疑这可能是获得我想要的便利的最不坏的方式。

  2. 使用将每个国家/地区的字符串名称连接到 states 表的应用程序逻辑创建一个视图。

  • 我不喜欢这个,因为如果应用程序逻辑中断,表格的可读性就会降低。此外,我希望大型连接操作比字符串 PK/FK 的性能损失更严重。
  1. 创建一个单独的表以将数字 ID 与适当的字符串 ID 连接起来。我不确定是否最好有一个表来编码每种类型的关系,或者一个大表有一个大的 ID 池,涵盖所有整数键-字符串值关系。然后,我可以使用应用程序逻辑来查找适当的字符串,并在用户给出字符串名称时将适当的 PK 填充到子表中。
  • 我觉得这也可能非常耗费资源,因为每次向子项添加新行时都必须进行查找。这也意味着我仍然必须创建我想要的视图。
  1. 使用enum数据类型。本能地,这将是我的首选方法,因为它似乎是自然键和合成键之间的理想平衡:使用整数 ID 并给 ID 一个字符串标签,这样字符串本身就不需要重复。
  • 不幸的是,我的研究发现不建议这样做。原因之一是类别不能轻易删除。我不确定这对我来说是否会破坏交易,但我也想知道为什么 DBMS 是这样设计的。分类变量是否常用到足以为它们添加便利功能?
foreign-key primary-key
  • 1 1 个回答
  • 506 Views

1 个回答

  • Voted
  1. Best Answer
    J.D.
    2022-07-25T12:42:17+08:002022-07-25T12:42:17+08:00

    虽然 ypercube 为 的特定示例提出了一个很好且合乎逻辑的观点,但Countries我会避免使用基于字符串的数据类型,因为不同数据库系统对字符串所做的某些假设可能会产生潜在的意外影响。例如,在 Microsoft SQL Server 中,优化器通常假设VARCHAR列是半满的,并将根据该假设生成请求内存的执行计划。这可能会导致内存资源分配过多(甚至不足)以服务于单个查询。我想其他数据库系统也会围绕基于字符串的数据类型做出其他有趣的假设,无论好坏。

    但比性能更重要的是数据准确性。表的首要任务是存储数据,并且最好准确地存储它。主键的首要任务是建立唯一性,理想情况下它应该是不可变的。代理键的好处是确保所有这些事情在人类可读的值能够改变的情况下保持真实。这实际上遵循了另一个称为one-field one- purpose的良好原则,因为代理键的含义与业务对象的含义完全分离。

    回到您的Countries示例, a 的名称会更改并不常见Country,但这也不是不可能的。在过去的 50 年中,一些国家改变了名称。即使使用 ISO 代码也不能 100% 保证它永远不会改变,Country因为这些代码是如何生成的(尽管从业务对象中移除比使用业务的人类可读值更多)对象本身)。

    因此,如果使用自然键值并且很可能在它发生变化的那一天发生变化,那么现在您将面临数据准确性的风险,因为您不仅需要确保Countries正确更新表,还必须对引用的每个表执行相同的操作Countries在外键中。

    当然,更新引用旧值的每条记录也会产生额外的性能开销,而不是在将代理键用作主键时仅在一个地方更新它。但在我看来,更大的问题(回到表格的主要目标)是数据准确性。

    视图是统一、转换和呈现数据到应用层的出色工具,在某些情况下(例如当您的表结构需要更改时)甚至可以帮助进行数据维护。由于视图可以充当应用程序和数据库表之间的一层,因此在更改这些表的结构时应用程序的风险较小。从性能的角度来看,使用它们本质上没有任何问题,并且JOIN性能(通过代理键)不应该是正确架构和索引数据库的问题。


    什么时候使用特殊的查找表进行 JOIN 与在父表中具有人类可读的列并让它们通过层次结构继承更好?

    这取决于。由于缺乏更清晰的方式来描述它,通常当它当前在它所在的主表中重复时,将人类可读的值重构到一个单独的表中是有意义的。这样就有一个地方可以唯一地定义该值可以轻松准确地维护。如果做得好,这将大致遵循规范化的原则。

    如果“特殊查找表”是指用于多种对象的单个表(例如您的帖子提到的枚举表),我不建议这样做。它可能比多个单独的对象表更容易维护,但是您会丢失关系数据库系统的一些关系属性。


    为什么代理键不能具有作为 FK 在所有用途中传播的可变字符串标签?

    这主要是说数据的准确性。没有什么能阻止您这样做,这不是最佳实践,因为增加了数据准确性的风险,并且在您需要更新值时使数据管理更加困难和性能降低。如果它是外键表中的一个常见值,那么您将面临锁定升级的风险,从而可能导致更长的等待时间并阻塞对该表的读取查询。


    为什么不通过为新州创建一个新行+一个存在多年的列来处理不断变化的国家名称?

    有些人实现了这种设计,但更多的是因为他们的业务规则和用例依赖于历史数据跟踪。但是对于具有标准用例的常规事务数据库,它会膨胀您的数据,并且仍然无法解决上述外键引用,您也必须使用更改更新它们或膨胀这些表。即使我有维护历史数据的用例,我也会将交易历史与活动记录分开存储在单独的历史表中。

    • 6

相关问题

  • 包含表的所有列的主键有什么好处吗?

  • 从复合键中删除字段并整理重复数据

  • 外键违规 - 不知道为什么

  • 使用 UUID 或 GUID 作为主键有什么缺点?

  • 字符与整数主键

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve