2

我只是想知道这里的最佳解决方案是什么。

假设我有一个规范化的数据库。整个系统的主键是一个varchar。我想知道我应该将此 varchar 与 int 关联以进行规范化还是保留它?保留为 varchar 更简单,但可能更理想

例如我可以有

People
======================
name      varchar(10)   
DoB       DateTime    
Height    int  

Phone_Number
======================
name      varchar(10)   
number    varchar(15)

或者我可以

People
======================
id        int Identity   
name      varchar(10)   
DoB       DateTime  
Height    int  

Phone_Number
======================
id        int   
number    varchar(15)  

当然,还要添加几个其他的一对多关系。

大家怎么看?哪个更好?为什么?

4

7 回答 7

10

我相信大多数开发过任何大型现实世界数据库应用程序的人都会告诉您代理键是唯一现实的解决方案。
我知道学术界会不同意,但这就是理论纯度和实用性之间的区别。

任何必须在使用非代理键的表之间进行连接的合理大小的查询,其中一些表具有复合主键,很快就会变得不可维护。

于 2008-09-27T19:28:47.010 回答
7

你真的可以使用名称作为主键吗?几个人同名的风险不是很大吗?

如果您真的很幸运,您的 name 属性可以用作主键,那么 - 无论如何 - 使用它。但是,通常您必须编造一些东西,例如 customer_id 等。

最后:“NAME”是至少一个 DBMS 中的保留字,因此请考虑使用其他名称,例如全名。

于 2008-09-27T17:59:44.417 回答
6

使用任何类型的非合成数据(即来自用户的任何数据,而不是由应用程序生成的数据)作为 PK 都是有问题的;您必须担心文化/本地化差异、区分大小写(以及其他取决于数据库排序规则的问题),如果/当用户输入的数据发生变化时,可能会导致数据问题等。

使用非用户生成的数据(顺序 GUID(如果您的数据库不支持它们或您不关心页面拆分,则为非顺序)或身份整数(如果您不需要 GUID))更容易,并且安全得多。

关于重复数据:我看不出使用非合成密钥如何保护您免受这种影响。您仍然会遇到用户输入“Bob Smith”而不是“Bob K. Smith”或“Smith, Bob”或“bob smith”等的问题。无论您的密钥是否是合成的,重复管理都是必要的(并且几乎相同)或非合成和非合成密钥有许多其他潜在问题,合成密钥可以巧妙地避免。

许多项目不需要担心这一点(例如,严格限制的排序规则选择会避免其中的许多),但总的来说,我更喜欢合成键。这并不是说有机键不能成功,显然可以,但对于许多项目来说,它们并不是更好的选择。

于 2008-09-27T18:15:24.550 回答
3

我认为如果您的 VARCHAR 更大,您会注意到您在整个数据库中复制了相当多的数据。而如果您使用数字 ID 列,则在将外键列添加到其他表时,您不会复制几乎相同数量的数据。

此外,就比较而言,文本数据是一种皇家痛苦,当您执行WHERE id = user_idWHERE name LIKE inputname(或类似的东西)时,您的生活会容易得多。

于 2008-09-27T18:05:17.600 回答
1

如果“名称”字段确实适合作为主键,那么就这样做。在这种情况下,通过创建代理键不会使数据库更加规范化。您将获得一些外键重复的字符串,但这不是规范化问题,因为 FK 约束保证字符串的完整性,就像它在代理键上一样。

但是,您并没有解释“名称”是什么。在实践中,字符串很少适合作为主键。如果是一个人的名字,就不能PK,因为多人可以同名,人可以改名等等。

于 2008-09-27T19:46:39.837 回答
1

其他人似乎没有提到的一件事是 int 字段上的连接往往比 varchar 字段上的连接性能更好。

而且我肯定会始终使用代理键而不是使用(人或企业的)名称,因为它们永远不会随着时间的推移而唯一。例如,在我们的数据库中,我们有 164 个名称,其中有超过 100 个同名实例。这清楚地表明了考虑使用名称作为关键字段的危险。

于 2008-09-27T20:56:41.637 回答
1

最初的问题不是标准化问题。如您所说,如果您有一个规范化的数据库,那么出于规范化的原因,您不需要更改它。

你的问题确实有两个问题。首先是整数或 varchars 是否更适合用作主键和外键。第二个是你是否可以使用问题定义中给出的自然键,或者你是否应该生成一个合成键(代理键)来代替自然键。

int 比 varchars 更简洁一些,并且对于诸如索引处理之类的事情更有效。但差异并不是压倒性的。您可能不应该仅在此基础上做出决定。

提供的自然键是否真的作为自然键起作用的问题要重要得多。“名称”列中的重复问题并不是唯一的问题。还有一个问题是当一个人改变她的名字时会发生什么。这个问题可能不会在您给出的示例中出现,但它确实会出现在许多其他数据库应用程序中。一个例子是一个学生四年的所有课程的成绩单。一个女人可能会在四年内结婚并改名,现在你被困住了。

您要么必须保持名称不变,在这种情况下它不再与现实世界一致,要么在此人参加的所有课程中追溯更新它,这使得数据库与当时制作的打印名册不一致。

如果您决定使用合成密钥,您现在必须决定应用程序是否要向用户社区揭示合成密钥的价值。那是另一个完整的蠕虫罐头,超出了本次讨论的范围。

于 2008-09-28T19:40:09.220 回答