Sql 主键还是唯一索引?

Sql 主键还是唯一索引?,sql,database,database-design,Sql,Database,Database Design,在工作中,我们有一个具有唯一索引的大型数据库,而不是主键,所有这些都可以正常工作 我正在为一个新项目设计新的数据库,我遇到了一个难题: 在DB理论中,主键是基本元素,这没关系,但在实际项目中,两者的优缺点是什么 你在项目中使用什么 编辑:…那么MS SQL server上的主键和复制呢?您可以这样看: 主键是唯一的 唯一值不必是元素的表示形式 什么意思?;主键用于识别元素,如果你有一个“人”,你希望有一个个人身份号码(SSN或类似号码),这是你的人的主要身份号码 另一方面,此人可能有一封唯一的电

在工作中,我们有一个具有唯一索引的大型数据库,而不是主键,所有这些都可以正常工作

我正在为一个新项目设计新的数据库,我遇到了一个难题:

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

你在项目中使用什么


编辑:…那么MS SQL server上的主键和复制呢?

您可以这样看:

主键是唯一的

唯一值不必是元素的表示形式

什么意思?;主键用于识别元素,如果你有一个“人”,你希望有一个个人身份号码(SSN或类似号码),这是你的人的主要身份号码

另一方面,此人可能有一封唯一的电子邮件,但无法识别此人


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

如果某个内容是主键,则根据数据库引擎的不同,整个表将按主键排序。这意味着对主键的查找速度要快得多,因为它不必像对任何其他类型的索引那样进行任何解引用。除此之外,这只是理论。

除了其他答案所说的以外,一些数据库和系统可能需要一个主数据库。我想到一种情况;将enterprise replication与Informix一起使用时,表必须有PK才能参与复制。

只要不允许值为NULL,它们的处理方式应该相同,但在数据库上对NULL值的处理方式不同(AFAIK MS-SQL不允许多个(1)空值,mySQL和Oracle允许,如果列是唯一的)
因此,您必须定义此列的非空唯一索引

主键没有缺点

为了向@MrWiggles和@Peter Parker answers添加一些信息,例如,当表没有主键时,您将无法编辑某些应用程序中的数据(他们最终会说没有主键无法编辑/删除数据)。Postgresql允许多个空值位于唯一列中,主键不允许空值。另外,一些生成代码的ORM可能在没有主键的表中存在一些问题

更新:


据我所知,在MSSQL中复制没有主键的表是不可能的,至少没有问题()。

外键与唯一约束以及主键一起工作。网上图书:

外键约束不存在 仅链接到主键 另一个表中的约束;它可以 也可以定义为引用 中唯一约束的列 另一张桌子

对于事务性复制,您需要主键。网上图书:

为事务性应用程序发布的表 复制必须具有主键。 如果一个表处于事务模式中 复制发布,您不能 禁用所有不可用的索引 与主键列关联。 这些索引是 复制。要禁用索引,请执行以下操作: 必须先把桌子从桌子上放下 出版


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

在关系数据理论中没有主键,因此您的问题必须在实践层面上得到回答

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

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


我喜欢声明主键。这具有禁止键列中为空以及禁止重复的效果。我还喜欢声明引用约束以强制实体完整性。在许多情况下,在外键的coulmn上声明索引将加快连接速度。这种索引通常不应该是唯一的。

我几乎从不创建没有数字主键的表。如果还有一个自然键应该是唯一的,我也会在它上面放一个唯一的索引。整数上的联接比多列自然键更快,数据只需要在一个位置更改(自然键往往需要更新,这在主键-外键关系中是一件坏事)。如果需要复制,请使用GUID而不是整数,但在大多数情况下,我更喜欢用户可读的密钥,尤其是当他们需要查看它以区分John Smith和John Smith时


我不创建代理键的几次是当我有一个参与多对多关系的联接表时。在本例中,我将这两个字段声明为主键

选择何时使用代理主键而不是自然键很棘手。诸如“永远”或“永远”之类的答案很少有用。我发现这要视情况而定

例如,我有以下表格:

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\u boots
cars
)和一个事务表(
drive\u through
)。
toll\u booth
表使用代理键,因为它没有不能保证更改的自然属性(名称很容易更改)。
cars
表使用自然主键,因为它具有不变的唯一标识符(
vin
)。
drive_-through
事务表使用代理键以便于识别,但对保证在当时唯一的属性也有唯一约束 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'