主键还是唯一索引?

Cic*_*cik 120 sql database database-design

在工作中,我们有一个大型数据库,具有唯一索引而不是主键,一切正常.

我正在为一个新项目设计新的数据库,我有一个两难的境地:

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

你在项目中使用了什么?

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

Mar*_*ers 161

什么是独特的指数?

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

CREATE TABLE table1 (foo int, bar int);
CREATE UNIQUE INDEX ux_table1_foo ON table1(foo);  -- Create unique index on foo.

INSERT INTO table1 (foo, bar) VALUES (1, 2); -- OK
INSERT INTO table1 (foo, bar) VALUES (2, 2); -- OK
INSERT INTO table1 (foo, bar) VALUES (3, 1); -- OK
INSERT INTO table1 (foo, bar) VALUES (1, 4); -- Fails!

Duplicate entry '1' for key 'ux_table1_foo'

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

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

可以在多列上创建唯一索引.

主键与唯一索引

事情是一样的:

  • 主键意味着唯一索引.

不同的事情:

  • 主键也暗示NOT NULL,但唯一索引可以为空.
  • 只能有一个主键,但可以有多个唯一索引.
  • 如果没有定义聚簇索引,则主键将是聚簇索引.

  • 请注意**唯一索引是列*上的索引并不完全准确,因为一个唯一索引或主键可以包含多个列. (4认同)
  • @Alexandre Jasmin:非常感谢.关于多列的部分将在后面提到. (2认同)
  • 但我仍然没有得到它,比如何时使用主键或何时使用唯一索引?或者可能是在相同的情况下. (2认同)

Fil*_*erg 32

你可以这样看:

主键是唯一的

唯一值不必是元素的表示

含义?; 好吧,主键用于标识元素,如果您有"人",您希望拥有个人识别号码(SSN或类似物),这是您的主要人物.

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

我总是有主键,甚至在关系表(中间表/连接表)中我可能有它们.为什么?好吧,我喜欢在编码时遵循标准,如果"人"有标识符,汽车有标识符,那么人 - >车也应该有标识符!

  • 主键(person_id,car_id)将是最好的.但我通常会创建一个新列,确定它会带来一些开销,但我认为它很好.您永远不知道是否要在以后的场景中与特定关系相关联. (3认同)
  • 如果你要生孩子,你只需要一把钥匙.如果值无处可去,为什么要添加列和序列,如果该值无用?这是为了阻止Access要求PK而进行的工作.如果您需要识别孩子的记录,请制作PK,否则这是浪费. (2认同)
  • 如果它与关系无关,它与它有什么关系?你指向一个领域并说,这是主要的.和?然后会发生什么?如果没有自然的pk,我会添加一个列,一个序列和一个触发器,因为____?有些人只需要成为小学.我没有理由地避开规则. (2认同)

Jon*_*oln 9

外键使用唯一约束以及主键.来自联机丛书:

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

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

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

这两个答案都适用于SQL Server 2005.


小智 5

选择何时使用代理主键而不是自然键是很棘手的.诸如,永远或永远的答案很少有用.我发现这取决于具体情况.

举个例子,我有以下表格:

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)
)
Run Code Online (Sandbox Code Playgroud)

我们有两个实体表(toll_boothscars)和一个事务表(drive_through).该toll_booth表使用代理键,因为它没有自然属性,无法保证更改(名称可以轻松更改).该cars表使用自然主键,因为它具有不变的唯一标识符(vin).该drive_through交易表使用便于标识的代理键,但也有对保证是在记录插入了时间的独特属性的唯一约束.

http://database-programmer.blogspot.com有一些关于这个特定主题的精彩文章.