主键还是唯一索引?

在工作中,我们有一个具有唯一索引而不是主键的大型数据库,所有工作都很好。

我正在devise一个新项目的新数据库,我有一个困境:

在DB理论中,主键是基本元素,没关系,但在REAL项目中,两者的优缺点是什么?

你在项目中使用什么?

编辑: …和MS SQL服务器上的主键和复制呢?

什么是独特的索引?

列上的唯一索引是该列上的一个索引,该索引还强制约束条件:在两个不同的行中,该列中不能有两个相等的值。 例:

 CREATE TABLE table1(foo int,bar int);
 CREATE UNIQUE INDEX ux_table1_foo ON table1(foo);  - 在foo上创build唯一的索引。

 INSERT INTO table1(foo,bar)VALUES(1,2);  -  好
 INSERT INTO table1(foo,bar)VALUES(2,2);  -  好
 INSERT INTO table1(foo,bar)VALUES(3,1);  -  好
 INSERT INTO table1(foo,bar)VALUES(1,4);  - 失败!

键“ux_table1_foo”的重复条目“1”

最后一个插入操作失败,因为它在第二次尝试将值1插入此列时违反了列foo上的唯一索引。

在MySQL中,一个唯一的约束允许多个NULL。

可以在多列上创build唯一的索引。

主键与唯一索引

事情是一样的:

  • 主键意味着唯一的索引。

事情不一样:

  • 主键也意味着NOT NULL,但唯一的索引可以是空的。
  • 只能有一个主键,但可以有多个唯一的索引。
  • 如果没有定义聚集索引,则主键将是聚簇索引。

你可以看到这样的:

主键是唯一的

一个唯一的值不一定是元素的表示

含义?; 那么主键是用来识别元素,如果你有一个“人”,你想有一个个人识别码(SSN或这样的)是你的人的主要。

另一方面,这个人可能会有一个独特的电子邮件,但不会识别这个人。

我总是有主键,即使在关系表(中表/连接表),我可能有他们。 为什么? 那么我喜欢在编码时遵循标准,如果“Person”有一个标识符,Car有一个标识符,那么Person – > Car也应该有一个标识符!

外键与独特的约束以及主键一起工作。 来自联机丛书:

FOREIGN KEY约束不必仅链接到另一个表中的PRIMARY KEY约束; 它也可以被定义为引用另一个表中的UNIQUE约束的列

对于事务复制,您需要主键。 来自联机丛书:

为事务复制发布的表必须具有主键。 如果某个表位于事务复制发布中,则无法禁用与主键列关联的任何索引。 这些索引是复制所必需的。 要禁用索引,您必须首先从发布中删除表。

两个答案都是针对SQL Server 2005的。

select何时使用代理主键而不是自然键是棘手的。 诸如永远或永远的答案很less有用。 我觉得这取决于情况。

作为一个例子,我有以下表格:

 CREATE TABLE toll_booths ( id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(255) NOT NULL, ... UNIQUE(name) ) CREATE TABLE cars ( vin VARCHAR(17) NOT NULL PRIMARY KEY, license_plate VARCHAR(10) NOT NULL, ... UNIQUE(license_plate) ) CREATE TABLE drive_through ( id INTEGER NOT NULL PRIMARY KEY, toll_booth_id INTEGER NOT NULL REFERENCES toll_booths(id), vin VARCHAR(17) NOT NULL REFERENCES cars(vin), at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, amount NUMERIC(10,4) NOT NULL, ... UNIQUE(toll_booth_id, vin) ) 

我们有两个实体表( toll_boothscars )和一个交易表( drive_through )。 toll_booth表使用代理键,因为它没有不能保证改变的自然属性(名称可以很容易地改变)。 cars表使用自然主键,因为它具有不变的唯一标识符( vin )。 drive_through事务表使用代理键以便于识别,但是对插入logging时保证唯一的属性也有一个唯一的约束。

http://database-programmer.blogspot.com在这个特定主题上有一些很棒的文章。;

主键没有缺点。

要添加一些信息到@MrWiggles和@Peter Parker的答案,当表没有主键,例如,你将无法编辑一些应用程序中的数据(他们最终会说,像不能编辑/删除数据没有首要的关键)。 Postgresql允许多个NULL值在UNIQUE列中,PRIMARY KEY不允许NULL。 还有一些生成代码的ORM在没有主键的表上可能会有一些问题。

更新:

据我所知,无法在MSSQL中复制没有主键的表,至less没有问题( 细节 )。

如果某项是主键,则取决于您的数据库引擎,整个表将按主键进行sorting。 这意味着查询在主键上的速度要快得多,因为它不必进行任何解引用,因为它必须处理任何其他种类的索引。 除此之外,这只是理论。

只要你不允许NULL值,它们应该被处理相同,但是在数据库中处理NULL的值是不同的(AFAIK MS-SQL不允许超过一个(1)NULL值,mySQL和Oracle允许这个,如果一列是唯一的)所以你必须定义这个列NOT NULL UNIQUE INDEX

关系数据理论中没有这样一个关键的东西,所以你的问题必须在实践层面上得到回答。

唯一索引不是SQL标准的一部分。 DBMS的特定实现将决定声明唯一索引的后果是什么。

在Oracle中,声明一个主键会导致代表你创build一个唯一的索引,所以这个问题几乎是没有意义的。 我不能告诉你其他DBMS产品。

我赞成声明一个主键。 这具有禁止键列中的空值以及禁止重复的效果。 我也赞成声明REFERENCES约束来强制实体的完整性。 在很多情况下,宣布一个外键的索引将加速联接。 这种指数通常不应该是唯一的。

除了其他的答案之外,有些数据库和系统可能需要一个主要的存在。 想到一种情况, 当使用Informix进行企业复制时,必须存在PK才能参与复制。

我几乎从不创build没有数字主键的表。 如果还有一个应该是独一无二的自然钥匙,那么我也会给它一个唯一的索引。 整数比多列自然键的联接更快,数据只需要在一个地方改变(自然键往往需要更新,这是一个坏的东西,当它在主键 – 外键关系)。 如果您需要复制,请使用GUID而不是整数,但在大多数情况下,我更喜欢用户可读的密钥,特别是如果需要查看密钥来区分John Smith和John Smith。

有几次,我不创build代理键是当我有一个多对多的关系中涉及的join表。 在这种情况下,我声明这两个字段为主键。

CLUSTERED INDEXES vs UNIQUE INDEXES有一些缺点。

如前所述,一个CLUSTERED INDEX物理地将数据sorting在表格中。

这意味着,如果在包含聚簇索引的表上插入或删除大量内容(每次(几乎取决于填充因子))更改数据,则需要更新物理表以保持sorting。

在相对较小的表格中,这样做很好,但是当获得具有GB值的数据的表格以及插入/删除会影响sorting时,就会遇到问题。

我的理解是,一个主键和一个非空约束的唯一索引是相同的(*); 我想根据规范明确规定或暗示的内容(你要expression和明确实施的内容)select一个或另一个。 如果它需要唯一性而不是null,那么把它作为主键。 如果只发生一个唯一索引的所有部分都不是空的,没有任何要求,那么就把它作为唯一的索引。

唯一的区别是,您可能有多个非空的唯一索引,而不能有多个主键。

(*)除了一个实际的区别:主键可以是一些操作的默认唯一键,如定义一个外键。 防爆。 如果定义了一个引用表的外键并且不提供列名,那么如果被引用的表具有主键,那么主键将是被引用的列。 否则,被引用的列将不得不被明确命名。

其他人在这里提到数据库复制,但我不知道。

唯一索引可以有一个NULL值。 它创build了非集群索引。 主键不能包含NULL值。 它创build了CLUSTERED INDEX。

在MSSQL中,主键应该单调递增,以便在聚簇索引上获得最佳性能。 因此,具有标识插入的整数比任何可能不会单调递增的自然键更好。