Sql server SQL Server事务表是否应该始终具有代理主键

Sql server SQL Server事务表是否应该始终具有代理主键,sql-server,database,sql-server-2008,database-design,Sql Server,Database,Sql Server 2008,Database Design,对于已经有主键(4列的自然组合键)的大型事务表(1亿行,20 GB),添加标识列并使其成为主键是否有助于提高性能 当前主键(4列的自然复合主键)完成了这项工作,但我被告知您应该始终拥有一个代理键因此,可以通过创建标识列并将其作为主键来提高性能? 我正在使用SQLServer2008R2数据库 编辑:此事务处理表主要与定义表联接,用于填充报告 编辑:如果我添加了一个代理键,它将不会在任何连接中使用。将使用现有的关键字段 编辑:此表将没有子表--EDIT: 根据对问题的编辑,添加标识/代理密钥可能不

对于已经有主键(4列的自然组合键)的大型事务表(1亿行,20 GB),添加标识列并使其成为主键是否有助于提高性能

当前主键(4列的自然复合主键)完成了这项工作,但我被告知您应该始终拥有一个代理键因此,可以通过创建标识列并将其作为主键来提高性能?

我正在使用SQLServer2008R2数据库

编辑:此事务处理表主要与定义表联接,用于填充报告

编辑:如果我添加了一个代理键,它将不会在任何连接中使用。将使用现有的关键字段

编辑:此表将没有子表--EDIT: 根据对问题的编辑,添加标识/代理密钥可能不是此问题的解决方案

——原始答案。

性能改进的一个例子是当您使用联接和有子表时

在缺少代理键的情况下,必须将所有th4键复制到子表中,并在4列上进行连接

t_parent
-------------
col1,
col2,
col3,
col4,
col5,
constraint pk_t_parent primary key (col1,col2,col3,col4)

t_child
----------
col1,
col2,
col3,
col4,
col7,
col8,
constraint pk_t_child primary key (col1,col2,col3,col4, col5),
constraint fk_parent_child foreign key (col1, col2, col3, col4) references
                                 t_parent ((col1, col2, col3, col4))
连接将包括所有4列

select t2.*
  from t_parent t1, t_child t2
  where (t1.col1 = t2.col1 and 
         t1.col2 = t2.col2 and 
         t1.col3 = t2.col3 and 
         t1.col4 = t2.col4
        )

如果使用代理键并在4列(现在是主键的一部分)上创建唯一约束,这将是高效的,并且数据仍将像以前一样进行验证。

仅添加标识列并为其添加新约束和索引不太可能提高性能。表将更大,因此扫描和查找可能需要更长的时间。还有更多的索引需要更新。当然,这一切都取决于你在衡量。。。以及在添加新列时是否打算对代码或数据库进行其他更改。添加标识列而不做其他事情可能是不明智的。

只有在以下情况下:

  • 您有更大的子表
  • 您有非聚集索引
在上述每种情况下,表的主键(假定聚集)将位于每个子条目/NC条目中。因此,使集群密钥更窄将受益

如果您只有非NC索引(可能只有一个)而没有子表,那么您将实现的就是

  • 更宽的行(使用更多的数据页)
  • 略小的B树(占总空间的一小部分)
…但是您仍然需要对当前的4列进行索引/约束=增加空间

如果您的4向键也捕获父表键(听起来很可能),那么您将失去重叠的优势。不过,新的索引/约束将涵盖这一点

所以不,你可能不想这么做


我们在十亿行以上的表上丢弃了一个代理键(bigint),改为实际的11路键,由于结构更简单(少一个索引,每页稍微多行等),磁盘空间减少了65%+

性能受损的一个地方是更改自然键中的数据。这一改变必须向所有儿童记录公布。例如,假设其中一个字段是company name,而该公司更改了它们的名称,那么所有相关记录(可能有数百万条)都必须更改,但如果使用代理键,则只需更改一条记录。整数联接往往更快(通常比4列联接快得多),编写代码进行联接通常也更快。然而,另一方面,拥有重要的四个字段可能意味着不需要经常进行连接。Insert PERFORMANCE EWILL将受到轻微的影响,并且必须生成代理密钥并为其编制索引。通常这是一个很小的打击,以至于不被注意到,但可能性是存在的

四列自然键通常不像您认为的那样是唯一的,因为数据的列数会随着时间的推移而变化。虽然它现在是独一无二的,但随着时间的推移,它会是独一无二的吗?如果在自然键上使用了代理键和唯一索引,但后来发现它不是唯一的,那么您所要做的就是删除唯一索引。如果是PK,并且存在子表,则必须完全重新设计数据库


只有您可以决定如果这些考虑因素中的任何一个影响到您的特定数据需求,那么代理键对某些应用程序更好,而对其他应用程序更差

考虑到您的编辑,以及该问题引发的所有对话,我建议在此表中添加一个标识列将弊大于利。

这是一个“视情况而定”类型的问题。加载事务数据后,您将如何处理它?您是否曾经需要根据元数据或其他事务表连接单个行?或者您主要使用聚合形式的事务数据?其他表中是否有相关的行?标识列实际上只在连接中有用-它将在较小程度上降低您对表的写入性能和空间。@Aaron:+1-“标识列实际上只在连接中有用”。@Aaron:谢谢您的评论。我已经更新了我的问题。@恶心:另一种可能的使用情况是,如果记录事务的应用程序要在其他地方记录一些东西,它可以使用SCOPE_IDENTITY()值而不是更宽的自然键,这反过来会使在调查结果出来时更容易返回并识别有问题的行。但就其本身而言,这似乎不是一种倾向于添加代理项的事情。@Aaron:默认情况下,我设计所有表都使用
int
bigint
标识
列作为带聚集索引的代理项主键。有很多文章支持这一点。当然有理由不这样做,但f