首页 文章

主键还是唯一索引?

提问于
浏览
109

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

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

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

你在项目中使用了什么?

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

15 回答

  • 4

    CLUSTERED INDEXES与UNIQUE INDEXES有一些缺点 .

    如前所述,CLUSTERED INDEX对表中的数据进行物理排序 .

    这意味着当你在包含聚簇索引的表上插入或删除很多时,每次(好吧,差不多,取决于你的填充因子)你更改数据,物理表需要更新以保持排序 .

    在相对较小的表中,这很好,但是当获得具有GB数据的表,并且插入器/删除器影响排序时,您将遇到问题 .

  • 29

    What is a unique index?

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

    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'
    

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

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

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

    Primary key versus unique index

    事情是一样的:

    • 主键表示唯一索引 .

    不同的事情:

    • 主键也暗示NOT NULL,但唯一索引可以为空 .

    • 只能有一个主键,但可以有多个唯一索引 .

    • 如果没有定义聚簇索引,则主键将是聚簇索引 .

  • 5

    你可以这样看:

    A Primary Key IS Unique

    A Unique value doesn't have to be the Representaion of the Element

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

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

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

  • 0

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

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

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

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

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

  • 0

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

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

    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 事务表使用代理键以便于识别,但对于在插入记录时保证唯一的属性也有唯一约束 .

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

  • 8

    主键没有缺点 .

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

    更新:

    据我所知,在MSSQL中无法复制没有主键的表,至少没有问题(details) .

  • 1

    如果某些东西是主键,则根据您的数据库引擎,整个表将按主键排序 . 这意味着主键上的查找速度要快得多,因为它不必进行任何解除引用,因为它与任何其他类型的索引有关 . 除此之外,这只是理论 .

  • 2

    只要你不允许对一个值使用NULL,它们应该被处理相同,但是在数据库上处理值NULL是不同的(AFAIK MS-SQL不允许多于一个(1)NULL值,mySQL和Oracle允许这样做,如果一个列是UNIQUE)所以你 must 定义这个列NOT NULL UNIQUE INDEX

  • 0

    在关系数据理论中没有关键词,所以你的问题必须在实际层面得到回答 .

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

    在Oracle中,声明主键将导致代表您创建唯一索引,因此问题几乎没有实际意义 . 我无法告诉你有关其他DBMS产品的信息 .

    我赞成声明一个主键 . 这具有禁止键列中的NULL以及禁止重复的效果 . 我也赞成声明REFERENCES约束来强制实体完整性 . 在许多情况下,声明外键的coulmn(s)索引会加速连接 . 这种索引通常不应该是唯一的 .

  • 2

    除了其他答案所说的内容之外,一些数据库和系统可能需要存在主数据库 . 一种情况浮现在脑海中;在使用Informix进行企业复制时,必须存在PK才能使表参与复制 .

  • 1

    我几乎从不创建没有数字主键的表 . 如果还有一个应该是唯一的自然键,我还会在其上添加一个唯一索引 . 连接在整数上比在多列自然键上更快,数据只需要在一个地方进行更改(自然键往往需要更新,这在主键中是一件坏事 - 外键关系) . 如果您将需要复制,请使用GUID而不是整数,但在大多数情况下,我更喜欢用户可读的密钥,特别是如果他们需要看到它来区分John Smith和John Smith .

    我没有创建代理键的次数是我有一个涉及多对多关系的连接表 . 在这种情况下,我将两个字段声明为主键 .

  • 2

    我的理解是主键和具有非空约束的唯一索引是相同的(*);我想根据规范明确指出或暗示的内容(你要表达和明确强制执行的内容)选择一个或另一个 . 如果它需要唯一性而不是null,那么将它作为主键 . 如果只是发生了唯一索引的所有部分都不为null而没有任何要求,那么只需将其作为唯一索引 .

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

    (*)除了实际差异之外:主键可以是某些操作的默认唯一键,例如定义外键 . 防爆 . 如果定义引用表的外键并且不提供列名,如果引用的表具有主键,则主键将是引用的列 . 否则,必须明确命名引用的列 .

    这里的其他人提到了数据库复制,但我不知道 .

  • 1

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

  • 148

    在MSSQL中,主键应该单调增加,以便在聚簇索引上获得最佳性能 . 因此,具有标识插入的整数优于可能不是单调增加的任何自然键 .

  • 1

    您应该始终添加唯一的自动索引ID列 .

    然后,除了创建可更新视图或选择之外,您应该继续忽略该列的所有意图和目的 .

    例如,永远不要将ID列用作外键或将其用于应用程序中的查找 .

    主键主要由数据库使用本身是为了唯一地标识表中的每一行 .

    数据库识别逻辑记录而不是物理记录是有 Value 的 - 即多表选择或视图中rowid()的值是多少 .

    还要考虑创建可更新视图,必须包含视图中所有表的主键 - 为每个表包含单个id列要容易得多,而不是必须包含每个表的复合主键的所有部分 . 表 .

    总之,数据库及其优化器使用主键 - 应用程序不应将其用于创建可更新视图以外的任何其他内容 . 应用程序所需的所有查找和关系应由所需列上的索引支持,并且应明确不使用主键 .

    在数据库的更深层次上,通常rowid()可以为每一行提供一个uniqie密钥,但它识别表中的物理行,而不是逻辑行 - 前者可以通过维护操作进行修改,而后者将始终识别独特的逻辑行 .

    其他索引很可能实际上是将索引键值映射到主键值,而不是rowid() . 这允许在不必重新创建这些索引的情况下进行物理排序操作 .

相关问题