在关系数据库中查找表的最佳实践是什么?

Nis*_*ant 16 foreign-key database-design best-practices primary-key

查找表(或一些人称之为代码表)通常是可以为特定列给出的可能值的集合。

例如,假设我们有一个名为party(用于存储有关政党的信息)的查找表,它有两列:

  • party_code_idn,它保存系统生成的数值,并且(缺乏业务领域含义)用作真实键的代理。
  • party_code, 是表的真实或“自然”键,因为它维护具有业务领域内涵的值。

让我们说这样的表保留了以下数据:

 +----------------+------------+
 | party_code_idn | party_code |
 +----------------+------------+
 |              1 | Republican |
 |              2 | Democratic |
 +----------------+------------+
Run Code Online (Sandbox Code Playgroud)

party_code列,这使价值“共和”和“民主”,在工作台的真正的关键,是建立了一个独特的约束,但我需要添加的party_code_idn,它定义为表(的PK虽然,从逻辑上说,party_code可以作为 PRIMARY KEY [PK])。

指向事务表中的查找值的最佳实践是什么?我应该建立外键 (FK) 引用(a)直接指向自然和有意义的值还是(b)代理值?

选项(a),例如,

 +---------------+------------+---------+
 | candidate_idn | party_code |  city   |
 +---------------+------------+---------+
 |             1 | Democratic | Alaska  |
 |             2 | Republican | Memphis |
 +---------------+------------+---------+
Run Code Online (Sandbox Code Playgroud)

具有以下属性1

  1. 最终用户可读 (+)
  2. 易于跨系统导入导出(+)
  3. 很难更改该值,因为它需要在所有引用表中进行修改 (-)
  4. 添加新价值并不昂贵 (=)

我认为这几乎就像“按值传递”,从应用程序编程术语中的函数调用中进行类比。

选项(b),例如,

 +---------------+----------------+---------+
 | candidate_idn | party_code_idn |  city   |
 +---------------+----------------+---------+
 |             1 |              1 | Alaska  |
 |             2 |              2 | Memphis |
 +---------------+----------------+---------+
Run Code Online (Sandbox Code Playgroud)

具有以下属性:

  1. 最终用户不可读 (-)
  2. 难以导入导出,因为我们需要取消引用它 (-)
  3. 易于更改值,因为我们只在事务表中存储引用(+)
  4. 添加新价值并不昂贵 (=)

如果与应用程序编程术语中的函数调用相比,它与“通过引用传递”非常相似。

导入-导出也可以用不同的方式完成,即,只需再次填充查找表,然后重新设置代理列。我希望我做对了,这是我刚刚听说的一种可能性。

1. 注意+,-=指出这些属性的好处。

非常重要的是:如果我们只想使用后一种方法,查找(或代码)表和 FK 引用之间有区别吗?我认为它们的工作原理相同。

相关资源

Mic*_*een 12

第三种方法具有您的两个选项的一些优点 - 将实际代码放入代码表中。我的意思是一个简短的字符序列,它捕捉了完整价值的本质并且是独一无二的。对于您给定的示例,它可能是

Idn: 1
Name: Democrats
Code: D      (or DEM)
Run Code Online (Sandbox Code Playgroud)

代码作为外键携带到事务表中。它简短、易懂,并且在某种程度上独立于“真实”数据。对a 名称的增量更改不会暗示代码更改。共和党是否应逃之夭夭集体,然而,代码的改变可能是必要的,以及伴随而来的问题,代孕的ID会不会产生。

这种风格被称为缩写编码。我可以推荐 Celko 在这方面的写作。谷歌图书有几个例子。搜索“Celko 编码”。

其他示例:国家/地区的 2 或 3 个字母编码,货币代码的 3 个字母编码(GBP、USD、EUR)。简短、不言自明且不会改变(并且它们有一个 ISO)。

Idn、Code 和 Name 中的每一个都是唯一的,因此每个都是候选键,并且可以选择任何一个作为主键。因此,对于给定 Idn 的示例,可以从表定义中删除,而使用代码。不同的 DBMS 以自己的方式处理整数和字符串,因此可能存在性能方面的考虑。在某些表中将 Idn 作为 FK 而在其他表中使用 Code 作为 FK 可能很有用。

  • @Fahmi Idn、代码和名称中的每一个都是唯一的,因此每一个都是候选键,并且可以选择任何一个作为主键。所以是的 - Idn 可以被删除。不同的 DBMS 以自己的方式处理整数和字符串,因此可能存在性能方面的考虑。在某些表中使用 Idn 作为 FK,在其他表中使用 Code 可能会很有用。 (2认同)

Vér*_*ace 11

通过IDN,我认为您的意思是IDENTITY,SEQUENCEAUTO_INCREMENT字段?你应该看看这里这里

注意,第 5 节(误用数据值作为数据元素),在图 10 下方

当然,您可以为销售人员创建一个单独的表,然后使用外键引用它,最好使用简单的代理键,如上所示的 sales_person_id 。

所以,这位专家认为你应该“尊重”代理键。它确实是一种非常基本的 SQL 技术,不会在您的日常 SQL 中引起问题。图 10 中似乎存在错误 - SalesData 中的 sales_person 应该是代理键(即数字),而不是文本。我从上面的引文中推断出这一点。

您应该不惜一切代价避免犯下第 (1) 节通用查找表中概述的错误的诱惑(对于新手数据库程序员来说非常常见)。这通常被称为 MUCK(大规模统一代码密钥)方法(并非偶然:-),尤其是Joe Celko,也被讽刺地称为OTLT - 一个真正的查找表)并导致各种困难。新手程序员似乎觉得单个代码/查找/任何表都是“更干净”的,并且在没有什么比事实更远的情况下会更有效率。

从上面的第二个参考:

规范化消除了冗余数据,从而使强制执行数据完整性的任务变得更加简单,但创建 MUCK 的过程完全是另一回事。 MUCK 不会消除冗余数据,而是消除了被认为是冗余表的内容,但是正如我将要展示的,更少的表并不等于简单。

您可能还想查看我在此处处理的相关 EAV(实体属性值)范例。