再来一次,旧的争论仍然浮现...
我们是否最好将业务密钥作为主键,还是宁愿使用在业务密钥字段上具有唯一约束的代理ID(即SQL Server身份)?
请提供示例或证明来支持您的理论。
再来一次,旧的争论仍然浮现...
我们是否最好将业务密钥作为主键,还是宁愿使用在业务密钥字段上具有唯一约束的代理ID(即SQL Server身份)?
请提供示例或证明来支持您的理论。
Answers:
都。吃蛋糕吃吧。
请记住,主键没有什么特别之处,只是它被标记为这样。它不过是一个NOT NULL UNIQUE约束,一个表可以有多个。
如果使用代理密钥,您仍需要一个业务密钥来确保根据业务规则的唯一性。
使用代理键的几个原因:
稳定性:由于业务或自然需求而更改密钥将对相关表产生负面影响。代理键很少(如果有的话)需要更改,因为与值无关。
约定:使您可以使用标准化的“主键”列命名约定,而不必考虑如何将具有各种名称的表联接到其PK。
速度:取决于PK值和类型,整数的替代键可能更小,索引和搜索更快。
似乎还没有人说过任何支持非代理(我犹豫要说“自然”)键的内容。所以这里...
代理键的一个缺点是它们无意义(某些人认为是优点,但是...)。有时这迫使您将比实际需要更多的表联接到查询中。相比:
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之类的表使用无意义的数字键,但不会对所有内容使用,这出于大多数人在某些情况下似乎都提倡的原因。
另请参阅:我对另一个问题的回答
代理键(通常是整数)具有使您的表关系更快,在存储和更新速度上更经济的附加值(更好的是,与业务键字段相比,使用代理键时不需要更新外键,确实会不时发生变化)。
表的主键应用于唯一地标识行,主要用于连接目的。考虑一个人表:名称可以更改,并且不能保证唯一。
Think公司:您是与Merkia中其他公司开展业务的快乐Merkin公司。您非常聪明,没有将公司名称用作主键,因此您可以使用Merkia政府的唯一公司ID(全部由10个字母数字字符组成)。然后Merkia更改了公司ID,因为他们认为这是个好主意。可以,您可以使用数据库引擎的级联更新功能进行更改,而该更改首先不应该涉及您。后来,您的业务扩展了,现在您在Freedonia的一家公司工作。Freedonian公司ID最多16个字符。您需要扩大公司ID主键(以及订单,发货,MoneyTransfers等中的外键字段),并在主键(也包括外键)中添加国家/地区字段。哎哟! 弗里多尼亚的内战,分为三个国家。您的同事的国家/地区名称应更改为新的国家/地区名称;级联更新以进行救援。顺便说一句,您的主键是什么?(国家/地区,公司ID)还是(国家/地区,公司ID)?后者有助于联接,前者避免另一个索引(或者,如果您也希望按国家/地区对订单进行分组,则可能避免多个索引)。
所有这些都不是证明,而是一种指示,用于唯一标识所有用途(包括联接操作)的行的代理键比业务键更可取。
我一般不喜欢替代键。仅当没有可用的自然键时才应使用它们。考虑一下这是很荒谬的,认为向表中添加无意义的数据可以使事情变得更好。
这是我的原因:
使用自然键时,表以最常搜索的方式聚集在一起,从而使查询速度更快。
使用代理键时,必须在逻辑键列上添加唯一索引。您仍然需要防止逻辑重复数据。例如,即使pk是代理ID列,您也不能在组织表中允许两个具有相同名称的组织。
当使用代理键作为主键时,自然主键是什么就不太清楚了。开发时,您想知道哪些列使表唯一。
在一对多的关系链中,逻辑钥匙链。因此,例如,组织有许多帐户,而帐户有许多发票。因此,组织的逻辑键是OrgName。帐户的逻辑键是OrgName,AccountID。发票的逻辑键是OrgName,AccountID,InvoiceNumber。
使用代理键时,仅对直接父级具有外键会缩短键链。例如,“发票”表没有“组织名称”列。它只有一个AccountID列。如果要搜索给定组织的发票,则需要加入组织,帐户和发票表。如果使用逻辑键,则可以直接查询组织表。
存储查找表的替代键值会使表中填充无意义的整数。要查看数据,必须创建连接到所有查找表的复杂视图。查找表旨在为列保留一组可接受的值。不应通过存储整数代理键来进行编码。规范化规则中没有任何内容建议您存储替代整数而不是值本身。
我有三本不同的数据库书籍。其中没有一个显示使用代理键。
我想与您分享我在这场无休止的战争中的经验:关于自然与替代关键难题的D。我认为,这两个代理键(人工自动生成的)和自然键(列(S组成)与域的意思)有优点和缺点。因此,根据您的情况,选择一种或另一种方法可能更相关。
似乎很多人将替代密钥作为几乎完美的解决方案,而将自然密钥作为瘟疫,因此,我将集中讨论另一种观点的论点:
代理键是:
在需要时使用自然键,在最好使用时使用代理键。
希望这对某人有所帮助!
在我看来,使用代理密钥比较好,因为更改的可能性为零。我几乎可以想到的任何可以用作自然键的东西都可能改变(免责声明:并不总是正确的,但通常是这样)。
一个示例可能是汽车数据库-乍一看,您可能会认为牌照可以用作钥匙。但是可以更改这些内容,所以这不是一个好主意。在发布应用程序后,您真的不想发现这一点,当有人来找您想知道为什么他们不能将其车牌更改为闪亮的个性化新车时。
languages
表中,因为表中已经存在语言代码(ID)texts
。
在数据仓库场景中,我认为最好遵循代理密钥路径。两个原因:
情况1:您的表是具有少于50种类型(插入)的查找表
使用业务/自然键。例如:
Table: JOB with 50 inserts
CODE (primary key) NAME DESCRIPTION
PRG PROGRAMMER A programmer is writing code
MNG MANAGER A manager is doing whatever
CLN CLEANER A cleaner cleans
...............
joined with
Table: PEOPLE with 100000 inserts
foreign key JOBCODE in table PEOPLE
looks at
primary key CODE in table JOB
情况2:您的表是具有数千个插入的表
使用代理/自动增量键。例如:
Table: ASSIGNMENT with 1000000 inserts
joined with
Table: PEOPLE with 100000 inserts
foreign key PEOPLEID in table ASSIGNMENT
looks at
primary key ID in table PEOPLE (autoincrement)
在第一种情况下:
在第二种情况下:
当业务信息可以更改或相同时,代理键可能很有用。毕竟,公司名称不必在全国范围内唯一。假设您与两家名为Smith Electronics的公司打交道,一家在堪萨斯州,另一家在密歇根州。您可以通过地址来区分它们,但是那会改变。甚至状态也可以改变。如果堪萨斯州堪萨斯城的史密斯电子公司过河而过,到密苏里州堪萨斯城怎么办?没有明显的方法可以使这些业务与自然密钥信息区分开,因此代理密钥非常有用。
将代理密钥想像成一个ISBN号。通常,您通过书名和作者来识别一本书。但是,我有两本HP Willmott题为“珍珠港”的书,它们绝对是不同的书,而不仅仅是不同的版本。在这种情况下,我可以参考书籍的外观,或者参考早期的书籍,还是参考后来的书籍,但是我也可以参考ISBN。
提醒一下,将聚簇索引放在随机代理键(即读取XY8D7-DFD8S的GUID)上不是一个好习惯,因为它们的SQL Server无法对这些数据进行物理排序。您应该改为在这些数据上放置唯一索引,尽管简单地对主表操作运行SQL事件探查器,然后将这些数据放入数据库引擎优化顾问也可能会有所帮助。
马课程。陈述我的偏见;我首先是一名开发人员,所以我主要关心的是为用户提供有效的应用程序。
我已经在使用自然键的系统上工作,并且不得不花费大量时间来确保价值变化会不断蔓延。
我在只有代理键的系统上工作,唯一的缺点是缺少用于分区的非规范化数据。
我曾与之合作的大多数传统PL / SQL开发人员都不喜欢代理键,因为每个连接的表数量很多,但是我们的测试和生产数据库从未冒过汗。多余的联接不会影响应用程序性能。对于不支持诸如“ Xa = Xb上的X内部联接Y”之类的子句的数据库方言,或者不使用该语法的开发人员,替代键的额外联接确实使查询更难阅读,并且键入和查询的时间更长。检查:请参阅@Tony Andrews帖子。但是,如果您使用ORM或任何其他SQL生成框架,您将不会注意到它。触摸输入也可以缓解。
也许与该主题不完全相关,但是我在处理代理密钥时感到头疼。Oracle预交付的分析会在仓库中的所有维度表上创建自动生成的SK,并且还会将它们存储在事实中。因此,每当添加新列或为维度中的所有项目填充时,都需要重新加载它们(维度),更新期间分配的SK使SK与存储在事实中的原始值不同步,从而迫使完全重新加载所有加入它的事实表。我希望即使SK是一个无意义的数字,在某种程度上也不会更改原始/旧记录。众所周知,开箱即用的产品很少能满足组织的需求,我们必须不断进行定制。现在我们的仓库中有3年的数据,而且从Oracle Financial系统完成的重新加载非常大。因此,就我而言,它们不是从数据输入生成的,而是添加在仓库中以帮助报告性能。我明白了,但是我们的确改变了,这是一场噩梦。
对于时间点数据库,最好将代理键和自然键组合在一起。例如,您需要跟踪俱乐部的会员信息。成员的某些属性永远不变。例如出生日期,但姓名可以更改。因此,使用member_id代理键创建一个Member表,并为DOB创建一列。创建另一个名为人员名的表,并在member_id,member_fname,member_lname,date_updated的列中添加列。在此表中,自然键为member_id + date_updated。