代理与自然/业务密钥

时间:2020-03-05 18:53:32  来源:igfitidea点击:

再来一次,旧的争论仍然浮现...

我们是否最好将业务密钥作为主键,还是宁愿使用在业务密钥字段上具有唯一约束的代理ID(即SQL Server身份)?

请提供示例或者证明来支持理论。

解决方案

回答

始终使用没有商业意义的密钥。这只是个好习惯。

编辑:我试图在线找到它的链接,但是我找不到。但是,在"企业架构模式" [Fowler]中,它很好地解释了为什么我们不应该使用除键以外的任何东西,而除了键之外,没有其他含义。归结为这样的事实,即它应该只有一份工作和一份工作。

回答

代理密钥永远不会有更改的理由。我不能对自然键说同样的话。姓氏,电子邮件,ISBN小数字,它们都可以在一天之内更改。

回答

在数据仓库场景中,我认为最好遵循代理密钥路径。两个原因:

  • 我们独立于源系统,并且那里的更改(例如数据类型更改)不会影响我们。
  • DW将需要较少的物理空间,因为我们将仅使用整数数据类型作为代理键。同样,索引将更好地工作。

回答

在我看来,使用代理密钥更好,因为更改的可能性为零。我几乎可以想到的任何可以用作自然键的东西都可能发生变化(免责声明:并不总是正确的,但通常是这样)。

一个示例可能是一眼的汽车数据库,我们可能会认为牌照可以用作钥匙。但是可以更改这些内容,所以这不是一个好主意。在发布应用程序之后,我们真的不想发现这一点,当有人来找我们想知道为什么他们不能将其车牌更改为闪亮的个性化新车时。

回答

代理键(通常是整数)具有增加表关系的添加值,并且在存储和更新速度方面更加经济(甚至更好,与业务键字段相比,使用代理键时不需要更新外键,确实会不时发生变化)。

表的主键应用于唯一地标识行,主要用于连接目的。考虑一个人表:名称可以更改,并且不能保证唯一。

Think公司:我们是与Merkia中其他公司开展业务的快乐Merkin公司。我们非常聪明,没有将公司名称用作主键,因此我们可以使用Merkia政府的唯一公司ID(全部由10个字母数字字符组成)。
然后Merkia更改了公司ID,因为他们认为这是个好主意。可以,我们可以使用数据库引擎的级联更新功能进行更改,而该更改首先不应该涉及我们。后来,业务扩展了,现在我们在Freedonia的一家公司工作。 Freedonian公司ID最多16个字符。我们需要扩大公司ID主键(以及订单,发货,MoneyTransfers等中的外键字段),并在主键(也包括外键)中添加国家/地区字段。哎哟!在弗里多尼亚的内战中,它分为三个国家。同事的国家/地区名称应更改为新的国家/地区名称;级联更新以进行救援。顺便说一句,主键是什么? (国家/地区,公司ID)或者(公司ID,国家/地区)?后者有助于联接,前者避免另一个索引(或者,如果我们也希望按国家/地区对订单进行分组,则可能避免多个索引)。

所有这些都不是证明,而是一种指示,用于唯一标识所有用途(包括联接操作)的行的代理键比业务键更可取。

回答

使用代理键的几个原因:

  • 稳定性:由于业务或者自然需求而更改密钥将对相关表产生负面影响。代理键很少(如果有的话)需要更改,因为与值无关。
  • 约定:使我们可以使用标准化的"主键"列命名约定,而不必考虑如何将具有各种名称的表联接到其PK。
  • 速度:根据PK值和类型,整数的替代键可能更小,索引和搜索更快。

回答

这是代理键几乎总是有意义的情况之一。在某些情况下,我们或者选择最适合数据库的对象,或者选择最适合对象模型的对象,但是在两种情况下,使用无意义的键或者GUID都是一个更好的主意。它使索引编制变得更加容易和快捷,并且它是对象的不变标识。

回答

如果我们打算使用ORM工具来处理/生成数据类,则代理键非常方便。虽然我们可以将组合键与某些更高级的映射器一起使用(阅读:休眠),但这会增加代码的复杂性。

(当然,数据库纯粹主义者会争辩说,即使代理密钥的概念也是可憎的。)

我喜欢在适当的时候使用uids作为代理键。与他们取得的主要胜利是我们提前知道了钥匙,例如我们可以创建一个类的实例,该实例的ID已经设置并且保证是唯一的,而使用整数键,则需要默认为0或者-1,并在保存/更新时更新为适当的值。

但是,UID在查找和连接速度方面会受到惩罚,因此,UID是否可取取决于所讨论的应用程序。

回答

始终使用单列,如果可能的话,使用替代键。这使联接以及插入/更新/删除操作更加整洁,因为我们仅负责跟踪一条信息以维护记录。

然后,根据需要,将业务密钥堆叠为唯一的约束或者索引。这将使我们保持数据完整性。

业务逻辑/自然键可以更改,但是表的物理键绝不能更改。

回答

两个都。吃蛋糕吃吧。

请记住,关于主键没有什么特别的,除了它被标记为这样。它不过是一个NOT NULL UNIQUE约束,一个表可以有多个。

如果使用代理密钥,我们仍需要一个业务密钥来确保根据业务规则的唯一性。

回答

似乎还没有人说过任何支持非代理(我犹豫要说"自然")键的内容。所以这里...

代理键的一个缺点是它们无意义(某些人认为是优点,但是...)。有时这迫使我们将比实际需要更多的表联接到查询中。比较:

select sum(t.hours)
from timesheets t
where t.dept_code = 'HR'
and t.status = 'VALID'
and t.project_code = 'MYPROJECT'
and t.task = 'BUILD';

反对:

select sum(t.hours)
from timesheets t
     join departents d on d.dept_id = t.dept_id
     join timesheet_statuses s on s.status_id = t.status_id
     join projects p on p.project_id = t.project_id
     join tasks k on k.task_id = t.task_id
where d.dept_code = 'HR'
and s.status = 'VALID'
and p.project_code = 'MYPROJECT'
and k.task_code = 'BUILD';

除非有人认真地认为以下是一个好主意?

select sum(t.hours)
from timesheets t
where t.dept_id = 34394
and t.status_id = 89    
and t.project_id = 1253
and t.task_id = 77;

"但是"有人会说,"当MYPROJECT或者VALID或者HR的代码更改时会发生什么?"我的回答是:"为什么要更改它?"从某种意义上说,这些不是"自然"键,某些外部主体将立法规定从此以后将" VALID"重新编码为" GOOD"。仅一小部分"自然"密钥确实属于该类别,SSN和Zip代码是通常的示例。我肯定会对诸如Person,Address之类的表使用无意义的数字键,但对于所有内容都不会使用,出于某些原因,这里的大多数人似乎都主张这样做。

另请参阅:我对另一个问题的回答

回答

当业务信息可以更改或者相同时,代理键可能会很有用。毕竟,公司名称不必在全国范围内唯一。假设我们与两家名为Smith Electronics的公司打交道,一家在堪萨斯州,另一家在密歇根州。我们可以通过地址来区分它们,但是那会改变。甚至状态也可以改变。如果堪萨斯州堪萨斯城的史密斯电子公司过河而过,到密苏里州堪萨斯城怎么办?没有明显的方法可以通过自然密钥信息来区分这些业务,因此代理密钥非常有用。

将代理密钥想像成一个ISBN号。通常,我们通过书名和作者来识别一本书。但是,我有两本H. P. Willmott题为"珍珠港"的书,它们绝对是不同的书,而不仅仅是不同的版本。在这种情况下,我可以参考书籍的外观,或者参考较早的版本,也可以参考较晚的版本,但是我也可以参考ISBN。

回答

对于时间点数据库,最好将代理键和自然键组合在一起。例如我们需要跟踪俱乐部的会员信息。成员的某些属性永远不会改变。例如出生日期,但姓名可以更改。
因此,使用member_id代理键创建一个Member表,并为DOB创建一列。
创建另一个名为人员名称的表,并在member_id,member_fname,member_lname,date_updated的列中添加列。在此表中,自然键为member_id + date_updated。

回答

我一般不喜欢替代键。仅当没有可用的自然键时才应使用它们。考虑一下这是很荒谬的,认为向表中添加无意义的数据可以使事情变得更好。

这是我的原因:

  • 使用自然键时,表以最常搜索的方式聚集在一起,从而使查询速度更快。
  • 使用代理键时,必须在逻辑键列上添加唯一索引。我们仍然需要防止逻辑重复数据。例如,即使pk是代理ID列,也不能在组织表中允许两个具有相同名称的组织。
  • 当使用代理键作为主键时,自然主键是什么就不太清楚了。在开发时,我们想知道哪些列集使表具有唯一性。
  • 在一对多的关系链中,逻辑钥匙链。因此,例如,组织有许多帐户,而帐户有许多发票。因此,组织的逻辑键是OrgName。帐户的逻辑键是OrgName,AccountID。发票的逻辑键是OrgName,AccountID,InvoiceNumber。使用代理键时,仅对直接父级具有外键,因此会截断键链。例如,"发票"表没有"组织名称"列。它只有一个AccountID列。如果要搜索给定组织的发票,则需要加入"组织","帐户"和"发票"表。如果使用逻辑键,则可以直接查询组织表。
  • 存储查找表的替代键值会使表中填充无意义的整数。要查看数据,必须创建连接到所有查找表的复杂视图。查找表旨在为列保留一组可接受的值。不应通过存储整数代理键来进行编码。规范化规则中没有任何内容建议我们存储替代整数而不是值本身。
  • 我有三本不同的数据库书籍。其中没有一个显示使用代理键。