Database 代理键与自然键:性能差异的硬数字?

Database 代理键与自然键:性能差异的硬数字?,database,database-design,primary-key,key,database-performance,Database,Database Design,Primary Key,Key,Database Performance,代理键和自然键之间存在着健康的争论: 我的观点似乎与大多数人一致(这是一个微弱的多数),即应该使用代理密钥,除非自然密钥是完全明显的,并且保证不会更改。然后,应该在自然关键点上强制唯一性。这意味着几乎所有时间都使用代理密钥 两种方法的示例,从公司表开始: 1:代理键:表有一个ID字段,它是PK(和标识)。国家要求公司名称是唯一的,因此有一个唯一的约束 2:自然键:表使用CompanyName和State作为PK——同时满足PK和唯一性 假设公司PK用于其他10个表中。我的假设是,在没有数字支

代理键和自然键之间存在着健康的争论:

我的观点似乎与大多数人一致(这是一个微弱的多数),即应该使用代理密钥,除非自然密钥是完全明显的,并且保证不会更改。然后,应该在自然关键点上强制唯一性。这意味着几乎所有时间都使用代理密钥

两种方法的示例,从公司表开始:

1:代理键:表有一个ID字段,它是PK(和标识)。国家要求公司名称是唯一的,因此有一个唯一的约束

2:自然键:表使用CompanyName和State作为PK——同时满足PK和唯一性

假设公司PK用于其他10个表中。我的假设是,在没有数字支持的情况下,代理键方法在这里会快得多

我所看到的关于自然键的唯一有说服力的论点是使用两个外键作为自然键的多对多表。我认为在这种情况下,这是有道理的。但是如果需要重构,您可能会遇到麻烦;我认为这超出了这篇文章的范围

有没有人看过一篇文章,比较使用代理键的一组表与使用自然键的同一组表的性能差异?环顾四周,谷歌并没有产生任何有价值的东西,只是大量的理论起草


重要更新:我已经开始建立一套回答这个问题的测试表。看起来是这样的:

  • PartNatural-使用 作为PK的唯一零件号
  • PartSurrogate-用于 使用ID(int,identity)作为主键和 零件号上有唯一索引
  • Plant-ID(int,identity)作为主键
  • 工程师-ID(int,标识)作为主键
每个零件都连接到工厂,工厂中的每个零件实例都连接到工程师。如果有人对这个试验台有问题,现在是时候了

自然关键点与代理关键点的区别在于值,而不是类型。 任何类型都可以用于代理键,如系统生成的
slug
或其他类型的
VARCHAR

但是,大多数代理键使用的类型是
INTEGER
RAW(16)
(或者
RDBMS
用于
GUID
的任何类型)

比较代理整数和自然整数(如
SSN
)需要的时间完全相同。 比较
VARCHAR
s会考虑排序规则,它们通常比整数长,这会降低效率

比较一组两个
整数
可能也比比较单个
整数
效率低

对于大小较小的数据类型,这种差异可能是获取页面、遍历索引、获取数据库锁存等所需时间的百分比

以下是数字(在MySQL中):

t_source
只是一个包含
1000000行的虚拟表

aint
adouble
bint
bdouble
包含完全相同的数据,除了
aint
有一个整数作为
主键,而
adouble
有一对相同的整数

在我的机器上,两个查询运行14.5秒+/-0.1秒
性能差异(如果有)在波动范围内。

两者都使用!自然键可以防止数据库损坏(不一致性可能是一个更好的词)。当“右”自然键(用于消除重复行)由于长度或涉及的列数而性能不佳时,出于性能目的,可以添加代理键,并将其用作其他表中的外键,而不是自然键。。。但自然密钥应保留为备用密钥或唯一索引,以防止数据损坏并加强数据库一致性


很多hoohah(在关于这个问题的“辩论”中)可能是由于一个错误的假设,即必须使用主键来连接其他表中的连接和外键。这是错误的。您可以使用任何键作为其他表中外键的目标。它可以是主键、备用键或任何唯一索引或唯一约束,只要它在目标关系(表)中是唯一的。至于连接,您可以使用任何连接条件,它甚至不必是键、索引,甚至不必是唯一的!!(尽管如果它不是唯一的,您将在它创建的笛卡尔乘积中获得多行)。您甚至可以使用非特定条件(如>)创建联接,这可能取决于代理键和自然键的数据类型,以及它们的索引方式等。考虑到人们使用代理键是因为它们在逻辑上是必要的,那么它们和自然键之间的性能差异(如果存在这种差异)必须是非实质性的-你不能用另一个替换一个。我认为自然键通常涉及varchar字段,代理键几乎总是int。虽然你是对的,但我希望我正在搜索的任何虚构的研究/白皮书都能解决这个问题。自然键涉及任何自然键。代理键可能是int、bigint、GUID等@jcollum不想在这里开始这场辩论,但无论是否存在自然键(几乎总是存在),都应该使用代理键。请注意我使用的短语“给定…”我看到的最常见的代理键与自然键的对比示例是States(在美国)表上的代理键应该是int,但自然键应该是char(2)。我想知道当美国超过1B人时,SSN是否会从int变为char。这真的不太遥远。哎呀,a
CREATE TABLE aint (id INT NOT NULL PRIMARY KEY, value VARCHAR(100));
CREATE TABLE adouble (id1 INT NOT NULL, id2 INT NOT NULL, value VARCHAR(100), PRIMARY KEY (id1, id2));
CREATE TABLE bint (id INT NOT NULL PRIMARY KEY, aid INT NOT NULL);
CREATE TABLE bdouble (id INT NOT NULL PRIMARY KEY, aid1 INT NOT NULL, aid2 INT NOT NULL);

INSERT
INTO    aint
SELECT  id, RPAD('', FLOOR(RAND(20090804) * 100), '*')
FROM    t_source;

INSERT
INTO    bint
SELECT  id, id
FROM    aint;

INSERT
INTO    adouble
SELECT  id, id, value
FROM    aint;

INSERT
INTO    bdouble
SELECT  id, id, id
FROM    aint;

SELECT  SUM(LENGTH(value))
FROM    bint b
JOIN    aint a
ON      a.id = b.aid;

SELECT  SUM(LENGTH(value))
FROM    bdouble b
JOIN    adouble a
ON      (a.id1, a.id2) = (b.aid1, b.aid2);