这些特定的表是否需要代理键?


13

背景

我有这张桌子

+-------------------------+  +------------------------+
|Airport                  |  |Country                 |
|-------------------------|  |------------------------|
|airport_code string (PK) |  |country_code string (PK)|
|address string           |  |name string             |
|name  string             |  +------------------------+
+-------------------------+

+-------------------------+
|Currency                 |
|-------------------------|
|currency_code string (PK)|
|name string              |
+-------------------------+

airport_codeIATA(国际航空运输协会)的 机场代码,乘飞机旅行时,您可以在行李标签中看到它们。

在此处输入图片说明

country_codeISO 3166-1 A3标准国家/地区代码,您可以在奥运会上查看它们。

在此处输入图片说明

currency_codeIS0 417标准的3个字符的货币代码,您可以在国际货币兑换显示板上看到它们。

在此处输入图片说明

问题

这些自然PK是否足够好?

是否使用世界公认的标准,而整个行业都接受了PK的标准?

这张桌子是否需要代孕品?

Answers:


15

不,他们没有。这些键绝对足够好!

他们是独一无二的,不是 很少去改变,有意义的,这是加大了代理键。这几乎就是一个好的PK的定义。

关于PK不可变和数字整数的限制不是关系模型(Codd's)或任何SQL标准(ANSI或其他)的一部分。


3
主键也必须是不可变的,而IATA机场代码绝对不是。可以根据IATA的要求随时更改它们。
詹姆斯·斯内尔

3
@JamesSnell-国际航空运输协会机场代码与国家代码一样不可变。如果您说的是一次变革,也许每十年一次。有关问题的讨论,请参见此处。还有许多过时的代码仍然存在,因为它们很难更改。此外,这就是CASCADE更新的目的。 如果不是很好的做法,则可变主键是合法的。
Bobson

2
@EricKing第三党恰好由许多行业的所有主要党派的代表组成,然后对标准进行了多年讨论,然后投票直至达成合理共识。他们还同意进行任何更改或添加新内容的机制。除此之外,创建代码列表标准并不是一时兴起的,而是因为存在着创建受控的,受尊重的,已达成共识的某项代码列表的需求,以便能够在全球范围内互操作并在全球范围内正确通信。
图兰斯·科尔多瓦

2
@ user61852 -你可以说这些标准是主键。
Bobson

3
@Bobson:“仍然有很多过时的代码,因为它们很难更改”->可能是因为它们是主键?
Maciej

2

我认为“ 需要”是一个很强的词,从严格意义上讲,表可能不需要代理键

但是,如果这是我的数据库,无论如何我可能都会添加代理键。我可能不一定希望我的数据库设计依赖于一堆第三方(IATA,ISO),无论它们的标准多么稳定。或者,我可能根本不想依赖特定的标准(还有其他货币代码标准吗?我不知道)。我可能会使用代理键对我的表进行建模,如下所示:

+-------------------------+  +------------------------+
|Airport                  |  |Country                 |
|-------------------------|  |------------------------|
|airport_id       int (PK)|  |country_id     int (PK) |
|iata_airport_code string |  |iso_country_code string |
|icao_airport_code string |  +------------------------+
|faa_identifier    string |  
|address           string |  
|name              string |  
+-------------------------+

+-------------------------+
|Currency                 |
|-------------------------|
|currency_id int (PK)     |
|iso_currency_code string |
|name string              |
+-------------------------+

换句话说,除非那些行业标准代码对我的应用程序固有地重要,否则我不会将它们用作表的PK。它们只是标签。无论如何,我的大多数其他表都可能具有代理键,并且此设置将增加我的数据模型的一致性。“添加”代理密钥的成本很小。

根据一些评论进行更新:

如果不了解示例表的上下文,就不可能知道IATA机场代码对使用数据库的应用程序有多么重要。显然,如果IATA代码对于整个应用程序至关重要,并且在整个应用程序中普遍使用,那么经过适当的分析,将代码用作表的PK可能是正确的决定。

但是,如果该表只是在应用程序的几个角落使用的查找表,则IATA代码的相对重要性可能无法说明在数据库基础结构中如此突出的位置。当然,您可能需要在这里和那里的一些查询中加入其他联接,但是与进行研究以确保您完全了解制作IATA代码的含义相比,这可能是微不足道的。主键字段。在某些情况下,我不仅不在乎,而且我也不必关心 IATA代码。@James Snell在下面的评论是一个完美的例子,我可能不想担心会影响表的PK。

同样,设计的一致性也很重要。如果您有一个数据库,其中包含数十个均设计一致的代理键的表,然后还有一些将第三方代码用作PK的查找表,则会导致不一致。这不是完全坏,但是需要在文档中格外注意,因此可能不需要保证。他们是查找表,出于善意,仅使用代理键来保持一致性就可以了。

根据进一步的研究更新:

好的,好奇心使我困扰,我决定从问题中提供的链接开始,对IATA机场代码进行一些有趣的研究。

事实证明,国际航空运输协会代码不像问题所表明的那样普遍和权威。根据此页面

大多数国家/地区在其官方航空出版物中使用四字符国际民航组织代码,而不是国际航空运输协会代码。

此外,IATA代码和ICAO代码与FAA标识符代码不同,后者是识别机场的另一种方法。

我提出这些建议的目的不是要开始辩论哪种代码更好或更通用,更权威或更全面,而要确切表明为什么我不愿意围绕任意第三者标识符设计数据库结构,除非有特定的业务原因要这样做

在这种情况下,我认为通过放弃IATA代码(或任何第三者,可能会更改的代码)作为主键候选并使用代理键,可以使我的数据库结构更好,更稳定,更灵活。这样,我可以避免由于主键选择而可能出现的任何潜在陷阱。


1
那么,国际航空运输协会的标准对航空公司已经足够了,但对您而言却不足够?
图兰斯·科尔多瓦

1
当然,当您想从伦敦希思罗机场寻找行李时,您将必须一直走到机场桌,因为您做不到select * from baggage where airport_code = 'LHR',这意味着数据库只能用于抛出应用程序,这是一个非常狭窄且专有的应用程序这种方法,特别是当企业主是为数据库付费的人,因此拥有它时。另外,您还必须编写代码来完成日常工作,例如将数据从一个数据库导入另一个数据库,以避免PK细菌病。
图兰斯·科尔多瓦

1
IATA代码不是一成不变的,因此不能视为PK候选者。示例:代码IDL在纽约,直到将其重命名为JFK。IDL代码现在位于密西西比州。
James Snell 2013年

2
@EricKing国际航空运输协会(IATA)和国际标准化组织(ISO)关心代码是否足够稳定,唯一且被普遍接受。这与设计桌子的人的兴趣非常吻合。
TulainsCórdova'13

2
@ user61852-仅仅因为这些是标准代码,并不意味着航空公司系统将它们用作PK(也许您在此有更多的了解?)。进行如此大规模的级联更新似乎是一个非常糟糕的主意。
JeffO 2013年

1

虽然在字段上具有代理键是没有问题的,但可以考虑的是索引页大小本身也没有什么错。

由于这是一个关系数据库,因此您将进行大量的连接,并且具有数字类型的替代键可能会使数据库更易于处理,即索引页大小将较小,因此搜索槽的速度更快。如果这是一个小项目,那就没关系了,您会顺利完成工作,但是应用程序越大,您越想减少瓶颈。

具有BIGINT,INT,SMALLINT,TINYINT或任何类似整数的数据类型可能会为您省去一些麻烦。

就是我的2美分

更新:

小型项目-由几个人,甚至几十个人使用。小型项目,演示项目,个人使用项目,在没有经验的情况下展示技能时可添加到产品组合中的东西等。

大型项目-每天有成千上万的用户使用。您将为拥有庞大用户群的国家/国际公司构建一些产品。

通常会发生的情况是,选择的一些记录经常被选择,并且服务器会缓存结果以便快速访问,但是有时您需要不时访问一些不常用的记录,这时服务器将不得不进入索引页。(在上面带有机场名称的示例中,人们经常乘坐国内航空公司的航班,例如奇查戈->洛杉矶,但是人们从波士顿->津巴布韦飞行的频率是多少)

如果使用VARCHAR,则表示间距不均匀,除非数据始终相同(此时CHAR值更有效)。这使得搜索索引的速度变慢,并且由于服务器已经在忙于每秒处理成千上万的查询,它现在不得不浪费时间通过不均匀的索引,并在连接上再次执行相同的操作(这比慢于在未优化的表格上进行常规选择,以DW为例,其中尽可能少的联接可以加快数据检索的速度。另外,如果您使用的UTF也可能使数据库引擎混乱(我见过一些情况)。

就我个人而言,根据我自己的经验,正确组织索引可以使联接的速度提高约70%,而对整数列进行联接可以使联接的速度提高约25%(取决于数据)。 。随着主表开始增长并在这些表上使用它们,您宁愿让整数数据类型占用具有几个字节的列,而不是拥有VARCHAR / CHAR字段来占用更多空间。归结为节省磁盘空间,提高性能和关系数据库的整体结构。

另外,正如詹姆斯·斯内尔(James Snell)所述:

主键也必须是不可变的,而IATA机场代码绝对不是。可以根据IATA的要求随时更改它们。

因此,考虑到这一点,您宁愿更新1个绑定到数字的记录,而不必更新该记录和您要加入的表中的所有记录。


这是一个合理的想法,但是这些表的重点是每个表中只有有限数量的记录。如果您实际上用small project和来表示代码大小bigger,请进行更新以阐明其重要性。
Bobson

1
关于PK不可变和数字整数的限制不是关系模型(Codd's)或任何SQL标准(ANSI或其他)的一部分。
TulainsCórdova2013年

4
基于固定长度的短字符串(如ISO代码)的索引与整数一样快。基于可变长度的索引,长字符串则不是。
图兰斯·科尔多瓦

这就是我所说的(请参见上面的VARCHAR vs CHAR部分),我还没有机会测试固定长度的短字符串和数字整数,但是我确实有机会使用可变长度和整数来测试
Toni Kostelac

2
参加演出是一个稻草人。通常,使用自然键意味着您一开始就不需要联接。
Mike Sherrill'Cat Recall'13

1

如果您采用“我一直使用代理键”的方法,则可以绕过这种关注。这可能不是一件好事,因为对数据进行一些思考很重要,但是它无疑节省了很多时间,精力和精力。如果有人接受这个规则,那么列出的例子肯定是合格的,因为它几乎需要“代表大会”来进行更改。

使用这些自然键对数据库进行临时查询当然很有帮助。通过包含查找表来创建执行相同功能的视图也可以正常工作。现代数据库使用这种类型的东西做得更好,甚至可能无关紧要。

在某些特定于美国的情况下,标准发生了巨大变化:邮政编码从5-9位数字扩展,州缩写改为一致的2个字母,并取消了句号(还记得伊利诺伊州是伊利诺伊州的时间吗?),并且大多数世界需要应对Y2K。如果您有一个实时应用程序,其数据分布在世界各地,包含数十亿条记录,那么级联更新不是最好的主意,但是我们不是都应该在面临此类挑战的地方工作吗?使用该数据集,您可以自己对其进行测试,并给出一个更具差异性的答案。


+1好答案。在大多数情况下,人们在这个问题上非常教条。许多数据库设计者都具有巨大的自我意识,并认为自己是数据库和数据的所有者。其他人则认为可以确定数据的所有者只能通过特定的应用程序使用它,因为他无法理解它。他们还倾向于为将来可能发生或可能不会发生的事情做好准备,同时使每天完成的事情变得生死攸关,例如导入数据和编写查询。也未能产生任何支持他们观点的规范书目。
图兰斯·科尔多瓦

顺便说一句,“我一直使用代理键”规则不在关系模型(Codd's)或任何SQL标准中。Oracle数据字典方案尽可能使用自然键,而在其他实例中则使用人工键。PPDM(ppdm.org)还推荐了混合方法,并在模型中使用了混合方法。ANSI SQL标准对所有代理都没有说明。我认为全替代和全天然都是腐蚀性的。关系模型教的是一些自然的和替代的东西。
TulainsCórdova'13
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.