当我教学生如何在 MySQL Workbench 中创建表时,复习复选框键的含义总是很重要的。然后,我需要提醒他们,每个表都需要我们之前关于规范化的讨论中的自然键。我解释说自然键是一个复合候选键(由两个或多个列值组成),它自然地定义了表中每一行的唯一性。
然后,我们讨论代理键,它们通常是 ID 列键。我解释说代理键是由数据库中的序列驱动的。虽然许多数据库公开了序列的名称,但 MySQL 将序列视为表的属性。在面向对象的分析和设计 (OOAD) 中,这使得序列通过组合而不是聚合成为表的成员。代理键在表中也是唯一的,但绝不能像自然键一样用于确定唯一性。代理键也是候选键,例如唯一标识车辆的 VIN 号。
在精心设计的表格中,您总是有两个候选键:一个描述唯一行,另一个为其分配一个数字。虽然您可以使用任一候选键来执行连接,但您始终应该使用连接语句的代理键。这意味着您选择或选择代理候选键作为主键。然后,您为自然键建立一个唯一索引,它允许您使用人类可破译的单词查询任何唯一行。
MySQL Workbench 的列属性表为:
键 | 含义 |
---|---|
PK | 指定主键列。 |
NN | 指定非空列约束。 |
UQ | 为每一行指定一个包含唯一值的列。 |
BIN | 指定一个VARCHAR数据类型列,以便其值以区分大小写的方式存储。您不能将此约束应用于其他数据类型。 |
UN | 指定一列包含无符号数值数据类型。可能的值是 0 到数据类型的最大数量,如整数、浮点数或双精度数。当您同时选中 PK 和 AI 复选框时,值 0 是不可能的,这可确保列自动递增到列的最大值。 |
ZF | 指定零填充会在任何数字数据类型的前面填充零,直到所有空间都用完,这就像一个带有零的左填充函数。 |
AI | 指定AUTO_INCREMENT并且只应检查代理主键值。 |
所有代理键列都应选中PK、NN、UN和AI复选框。默认行为仅检查PK和NN复选框,而未选中UN和AI框。您还应该为所有代理键列单击带有AI复选框的UN复选框。AI复选框启用AUTO_INCREMENT行为。在将表迁移到双精度数之前,UN复选框可确保您拥有最大数量的整数。或多或少,这是我写的MySQL Workbench Data Modeling & Development作为 2013 年的主要产品指南,您可以在MySQL Workbench Manual 8.1.10.2 Columns Tab部分找到内容。
活动表快速增长,使用带符号的int意味着您更快地用完行。这是一个重要的设计考虑因素,因为使用 unsigned int会在以后添加维护任务。维护任务将需要在更改主键列的数据类型之前更改所有依赖外键列的数据类型。假设您的设计使用引用完整性约束,作为外键实现,您将需要:
- 在更改引用的主键和依赖外键列的数据类型之前删除任何外键约束。
- 更改主键和外键列的数据类型。
- 在更改引用的主键和依赖外键列的数据类型后添加回外键约束。
虽然对于大多数数据工程师来说,修复一个不太理想的设计是一个相对简单的脚本练习,但您可以避免这种维护任务。使用signed int作为初始数据类型来实现所有代理主键列和外键列。
下面的小 ERD 显示了一个多语言查找表,它比单语言枚举数据类型更可取:
当存在已知的选择列表时,设计使用查找表。如果不是所有业务应用程序,大多数业务应用程序中都会出现已知列表。维护该值列表是一项应用程序设置任务,并且需要开发团队构建一个条目并更新表单以输入和维护列表。
虽然一些 MySQL 示例通过使用 MySQL枚举数据类型来演示这些类型的列表。但是,MySQL枚举类型不支持多语言实现,不容易移植到其他关系数据库,并且有许多限制。
查找表是使用枚举数据类型的更好解决方案。它通常遵循以下模式:
- 确定列表有用的目标表和列。使用table_name和column_name列作为超级键来标识列表所属的位置。
- 标识列表的唯一类型标识符。将唯一类型值存储在查找表的类型列中。
- 使用lang列启用多语言列表。
table_name、column_name、type和lang的组合让您可以识别唯一集。您可以在这两个较早的博客文章中找到单语实现:
查找表的列视图显示了相应的设计复选框:
虽然大多数外键使用代理键的副本,但在某些情况下,您会从另一个表中复制自然键值而不是代理键。当您的应用程序将频繁查询依赖 查找表而不连接 lang表时,就会执行此操作,这意味着外键值应该是人类友好的外键值,可用作超级键。
超级键是唯一标识关系范围内的行的一列或一组列。对于此示例,lang列标识属于多语言数据模型中的一种语言的行。属于一种语言是查找和语言表之间的关系。从查找表中过滤具有特定lang值的行时,它也是一个键。
您导航到外键选项卡以创建lookup_fk外键约束,例如:
使用这种类型的外键约束,您可以在插入查找表值时从语言表中复制语言值。然后,您的 HTML 表单可以在任何受支持的语言中使用查找表的含义列,例如:
SELECT lookup_id
, type
, meaning
FROM lookup
WHERE table_name = 'some_table_name'
AND column_name = 'some_column_name'
AND lang = 'some_lang_name';
复制
WHERE子句中不使用类型列值来过滤数据集,因为它在table_name、column_name和lang列值的关系中是唯一的。当您排除lang列值时,它始终是非唯一的,并且对于table_name和column_name列值的另一个组合可能是非唯一的。
通常,大多数外键引用都指向查找表的代理主键,因为含义列的值太长而无法复制到引用表中,或者在基本语言或翻译语言中可能会发生变化。在许多实现中,具有内在含义的小值存储在代码列中,例如lang列。这些通常遵循与lang列相同的实现规则,并被复制到引用表中。
如果我留下了问题,请告诉我。我希望这有助于确定最佳设计实践。