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

时间:2014-02-13 18:01:06

标签: 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... )

三个基本选项(在所有情况下都假设在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是愚蠢和冗余的 - 并且不必要地在数据库引擎上引入了另一层约束检查。另一方面,一个成员声称多列主键是邪恶的(我不同意......但这不是问题)。因此,提出的一个折衷方案是让xref表只包含两个外键,并在这些列上定义唯一索引,但 not 根本不定义主键。

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

嗯,这完全取决于要求。据我所知

PRIMARY KEY= UNIQUE KEY+NOT NULL key

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

NOT NULL UNIQUE INDEXES(NON CLUSTERED)
      but

 CANNOT HAVE MULTIPLE PRIMARY KEYS IN A TABLE( CLUSTERED). 

我非常相信关系数据库模型并使用PRIMARY-FOREIGN KEYS关系。数据库复制要求您在表上拥有主键;因此,为表创建主键而不是UNIQUE键始终是一个好习惯。