首页 文章

使用唯一索引但没有主键在SQL Server中创建表有什么影响?

提问于
浏览
5

这个问题来自我的部门内部关于制作一个简单的多对多交叉引用表的最佳方法,该表只包含两列,这些列本身就是其他表中的主键 .

是否有人具有支持或反对创建具有单个唯一索引但没有主键的表的具体证据? (替代方案详述如下) .

换句话说:有没有人(特别是MSFT人员)知道SQL Server内部唯一地识别具有主键的行a)和b)没有主键的行?

In detail

给定输入表:

CREATE TABLE Foo ( FooID bigint identity(1,1) not null primary key, other stuff... )
CREATE TABLE Bar ( BarID bigint identity(1,1) not null primary key, other stuff... )

三个基本选项是(在所有情况下,假设在 FooIDBarID 列上创建了外键):

-- Option 1: Compound primary key
CREATE TABLE FooBarXRef ( 
    FooID bigint not null
  , BarID bigint not null
  , PRIMARY KEY ( FooID, BarID )
  , CONSTRAINT FK... etc
)

-- Option 2: Independent primary key + unique index
CREATE TABLE FooBarXRef ( 
    FooBarXRefID bigint identity(1,1) not null primary key
  , FooID bigint not null
  , BarID bigint not null
  , CONSTRAINT FK... etc
);
CREATE UNIQUE INDEX I_FooBarXRef_FooBar ON FooBarXRef ( FooID, BarID );

-- Option 3: Unique index, no explicit primary key:
CREATE TABLE FooBarXRef ( 
    FooID bigint not null
  , BarID bigint not null
  , CONSTRAINT FK... etc
);
CREATE UNIQUE INDEX I_FooBarXRef_FooBar ON FooBarXRef ( FooID, BarID );

我们中的一些人认为在外部参照表上使用单独的标识PK是愚蠢和冗余的 - 并且不必要地在数据库引擎上引入了另一层约束检查 . 另一方面,一个成员声称多列主键是邪恶的(我不同意..但这不是问题) . 因此,提出的一个折衷方案是使外部参照表仅包含两个外键,并在这些列上定义唯一索引,但根本不定义主键 .

我怀疑这样做会导致SQL Server创建一个内部主键,以便唯一标识每一行,从而产生相同的冗余约束,就像明确定义主键一样 - 但我没有证据或文档来支持这一点 . Other questions and answers建议默认情况下没有内部主键(即不等同于Oracle ROWID);因为 %%physloc%% 是当前存储行的位置的指示符,因此可能会发生变化 . 我的直觉是引擎必须创建一些东西来唯一地标识一行,以实现游标,事务和并发 .

2 回答

  • 2

    嗯,这一切都取决于要求 . 我所知道的

    PRIMARY KEY= UNIQUE KEY+NOT NULL key
    

    这告诉你的是你可以拥有多个

    NOT NULL UNIQUE INDEXES(NON CLUSTERED)
          but
    
     CANNOT HAVE MULTIPLE PRIMARY KEYS IN A TABLE( CLUSTERED).
    

    我是Relational数据库模型的忠实信徒,并且使用PRIMARY-FOREIGN KEYS关系 . 数据库复制要求您在表上具有主键;因此,为表创建主键而不是UNIQUE键始终是一个好习惯 .

  • 5

    主键的概念实际上是关系理论;通过在多个表之间 Build 关系来维护参照完整性 . 默认情况下,SQL Server引擎在构建主键时创建唯一的聚簇索引(假设此时不存在聚簇索引) .

    正是这个聚集索引在叶级别定义了一个唯一的行 . 对于具有非唯一聚簇索引的表,SQL Server会在键的末尾创建一个4字节的“uniquifier” .

    • TestTable1主键

    • TestTable2主键和唯一非群集

    • TestTable3 Unique Clustered

    • TestTable4 Primary Clustered(与Table1和Table3相同,因为主键可以在非聚集索引上定义,我更喜欢这个,以便始终定义我想要的结构) .

    TestTable2是多余的,它创建了一个唯一的聚簇索引来存储它叶级的所有记录 . 然后,它会创建一个唯一的非聚集索引,以再次强制实现唯一性 . 表上的任何更改都将命中群集,然后是非群集 .

    TestTable1,TestTable3,TestTable4在我的书中是一个平局,在所有上创建了一个独特的聚簇索引结构 . 记录在页面上的存储方式没有实质差异 .

    但是,对于SQL Server Replication,所有复制表都需要主键 . 如果您将来使用Replication,您可能希望确保所有唯一的聚簇索引也是主键 .

    我似乎无法粘贴我的验证脚本,所以这里他们在hastebin上 .

    http://hastebin.com/qucajimixi.vbs

相关问题