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

Jos*_*nig 5 sql-server primary-key

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

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

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

详细说明:

给定输入表:

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

三个基本选项是(在所有情况下都假设在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 );
Run Code Online (Sandbox Code Playgroud)

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

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

dee*_*eeg 5

主键的概念实际上是关系理论; 通过在多个表之间建立关系来维护参照完整性.默认情况下,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