sql - 6NF 中参照完整性的复合键与代理键

标签 sql database 6nf

取三层信息:

第 1 层:信息

该层包含具有UNIQUE 自然索引和易于传输的代理键的数据。

Table Surnames:

+-----------------------------+--------------+
|    ID (Auto Increment, PK)  |    Surname   |
+-----------------------------+--------------+
|               1             |     Smith    |
|               2             |    Edwards   |
|               3             |     Brown    |
+-----------------------------+--------------+

Table FirstNames

+-----------------------------+--------------+
|   ID (Auto Increment, PK)   |   FirstName  |
+-----------------------------+--------------+
|               1             |     John     |
|               2             |     Bob      |
|               3             |     Mary     |
|               4             |     Kate     |
+-----------------------------+--------------+

自然键

或者,上面的两个表可以没有 ID,并使用 Surname 和 FirstName 作为自然主键,如 Mike Sherrill 所解释的那样。在这种情况下,假设下面的层引用 varchar 而不是 int

第 2 层:人

在这一层中使用了复合索引。此值可以是 UNIQUEPRIMARY,具体取决于代理键是否用作主键。

+-----------------+--------------+
|    FirstName    |    LastName  |
+-----------------+--------------+
|        1        |       2      |
|        1        |       3      |
|        2        |       3      |
|        3        |       1      |
|        4        |       2      |
|       ...       |      ...     |
+-----------------+--------------+

第 3 层: parent

在这一层中,通过 ParentsOf 表探索人与人之间的关系。

ParentsOf

+-----------------+-----------------+
|      Person     |   PersonParent  |
+-----------------+-----------------+

 OR

+-----------------+-----------------+-----------------+-----------------+
| PersonFirstName |  PersonSurname  | ParentFirstName |  ParentSurname  |
+-----------------+-----------------+-----------------+-----------------+

问题

假设引用完整性在其核心对我来说非常重要,并且我将在这些索引上使用 FOREIGN KEYS,以便让数据库负责在这方面监控其自身的完整性,并且那,如果我要使用 ORM,它会像 Doctrine它具有对复合主键的 native 支持...

请帮助我理解:

  • 在第一层使用代理键与自然键的权衡列表。

  • 在第 2 层使用复合键与代理键的权衡列表,可以转移到第 3 层。

我不想听哪个更好,因为我知道专业人士在这个话题上存在重大分歧,这会引发一场宗教 war 。相反,我问的是,尽可能简单和客观地问,通过将代理键传递给每个层与维护主键(自然/复合,或代理/复合),你将采取什么权衡。任何人都可以找到有人说从不总是 在 SO 和其他网站上使用代理键。相反,我最希望在您的回答中对权衡进行合理的分析。

编辑:有人指出,姓氏示例不是使用 6NF 的不良示例。为了保持问题完整,我将保留它。如果您在想象这个用例时遇到困难,更好的一个可能是“杂货项目”列表。又名:

+-----------------------------+--------------+
|   ID (Auto Increment, PK)   |   Grocery    |
+-----------------------------+--------------+
|               1             | Sponges      |
|               2             | Tomato Soup  |
|               3             | Ice Cream    |
|               4             | Lemons       |
|               5             | Strawberries |
|               6             | Whipped Cream|
+-----------------------------+--------------+

+-----------------------------+--------------+
|   ID (Auto Increment, PK)   |   Brand      |
+-----------------------------+--------------+
|               1             | Bright       |
|               2             | Ben & Jerry's|
|               3             | Store Brand  |
|               4             | Campbell's   |
|               5             | Cool Whip    |
+-----------------------------+--------------+    

自然复合键示例:

+-----------------------------+--------------+
|           Grocery           |   Brand      |
+-----------------------------+--------------+
|           Sponges           | Bright       |
|           Ice Cream         | Ben & Jerry's|
|           Ice Cream         | Store Brand  |
|           Tomato Soup       | Campbell's   |
|           Tomato Soup       | Store Brand  |
|           Lemons            | Store Brand  |
|           Whipped Cream     | Cool Whip    |
+-----------------------------+--------------+ 

推荐配对

+-----------------+-----------------+-----------------+-----------------+
|     Grocery1     |  Brand1        | Grocery2        |  Brand2         |
+-----------------+-----------------+-----------------+-----------------+

重申一下,这也只是一个例子。这不是我建议的处理方式,但它应该有助于说明我的问题。

这种方法有不足之处。我要重申,这个问题是要求了解下面每种方法的优点和缺点,而不是强调一种方法比另一种方法更好。我相信大多数人都能够跳过这个具体示例的可疑性质来回答核心问题。此编辑适用于那些不能。

下面有一些很好的答案,如果您对去哪个方向感到好奇,请阅读它们。

结束编辑

谢谢!

最佳答案

这里有一些权衡:

单一代理(人工创建):

  • 所有子表的外键只需要一个列来引用主键。

  • 更新表中的自然键非常容易,无需使用外键更新每个子表

  • 较小的主/外键索引(即不宽)这可以使数据库运行得更快,例如当父表中的记录被删除时,需要搜索子表以确保这一点不会产生孤儿。窄索引扫描速度更快(只是视觉上)。

  • 您将拥有更多索引,因为您很可能还希望索引数据中存在的任何自然键。

自然复合键表:

  • 数据库中的索引较少

  • 减少数据库中的列

  • 更容易/更快地插入大量记录,因为您不需要获取序列生成器

  • 更新复合中的一个键需要同时更新每个子表。

然后还有一类:人工复合主键

我只找到一个有意义的实例。当您需要标记每个表中的每条记录以确保行级安全性时。

例如,假设您有一个数据库,其中存储了 50,000 个客户端的数据,并且每个客户端都不应看到其他客户端的数据——这在 Web 应用程序开发中很常见。

如果每条记录都标记有 client_id 字段,则您正在创建行级安全环境。大多数数据库都具有在正确设置时强制执行行级安全性的工具。

首先要做的是设置主键和外键。通常一个表有一个 id 字段作为主键。通过添加 client_id 键现在是复合键。并且所有子表都需要携带client_id

复合键基于 2 个代理键,是确保客户端之间和整个数据库内数据完整性的防弹方法。

在此之后,您将创建 View (或者如果使用 Oracle EE 设置虚拟专用数据库)和其他各种结构以允许数据库强制执行行级安全性(这是它自己的一个主题)。

假定此数据结构不再规范化为 n 次。每个 pk/fk 中的 client_id 字段对其他正常模型进行非规范化。该模型的好处是易于在数据库级别实现行级别安全性(这是数据库应该做的)。每个选择、插入、更新、删除都仅限于您当前设置的任何 client_id。数据库具有 session 感知

总结

代理键始终是安全的选择。他们需要更多的工作来设置并需要更多的存储空间。

我认为最大的好处是:

  • 能够更新一个表中的 PK,并且所有其他子表都会立即更改,而不会被触及。

  • 当数据变得困惑时——在某个时刻,由于编程错误,代理键会使清理变得容易得多,在某些情况下,只有代理键才有可能做到这一点。

  • 查询性能得到改进,因为数据库能够搜索属性以定位 s.key,然后通过单个数字键连接所有子表。

自然键尤其是复合 NKey 使编写代码变得很痛苦。当您需要连接 4 个表时,“where 子句”将比使用单个 SKey 时长得多(并且更容易搞砸)。

代理键是“安全”路由。自然键在一些地方是有用的,我会说数据库中大约 1% 的表。

关于sql - 6NF 中参照完整性的复合键与代理键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23850396/

相关文章:

sql - 为历史数据正确设计 EAV 数据库

database - 6NF 表可以包含外键吗?

sql - 在哪里可以找到有关第六范式的信息

c# - 如果 select 语句没有返回行,返回什么?

c# - 为什么 LinqToEntities Skip/Take oracle 实现如此缓慢

MySQL - 自己选择查询顺序

mysql - 代码点火器 : A Database Error Occurred SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client

php - MySQL - 无法更新多列

mysql - 使用 sql 来跟踪单词及其计数

sql - 访问 Azure 自动备份