没有主键的表

时间:2008-08-08 02:47:16

标签: sql-server indexing

我有几个表,其唯一的唯一数据是uniqueidentifier(Guid)列。因为guid是非顺序的(并且它们是客户端生成的所以我不能使用newsequentialid()),所以我在这个ID字段上创建了一个非主要的非聚集索引,而不是给表一个聚簇的主要键。

我想知道这种方法的性能影响。我见过一些人建议表应该有一个自动递增(“identity”)int作为聚簇主键,即使它没有任何意义,因为这意味着数据库引擎本身可以快速使用该值查找一行而不必使用书签。

我的数据库是在一堆服务器上进行合并复制的,所以我回避了identity int列,因为它们在复制方面有点毛茸茸。

你有什么想法?表应该有主键吗?或者,如果没有合理的列可以索引那么,是否可以没有任何聚簇索引?

7 个答案:

答案 0 :(得分:32)

处理索引时,您必须确定要用于表的内容。如果您主要是每秒插入1000行而不进行任何查询,那么聚集索引会影响性能。如果您每秒进行1000次查询,那么没有索引将导致非常糟糕的性能。尝试调优查询/索引时,最好的办法是在SQL Server中使用查询计划分析器和SQL事件探查器。这将显示您遇到昂贵的表扫描或其他性能阻止程序的位置。

至于GUID vs ID参数,您可以在网上找到两者都发誓的人。我一直被教导使用GUID,除非我有充分的理由不这样做。 Jeff发表了一篇很好的文章,讨论了使用GUID的原因:https://blog.codinghorror.com/primary-keys-ids-versus-guids/

与大多数与开发相关的事情一样,如果您希望提高性能,则没有一个单一的正确答案。这实际上取决于您要完成的任务以及如何实施解决方案。唯一真正的答案是再次针对性能指标进行测试,测试和测试,以确保您达到目标。

[编辑] @Matt,在对GUID / ID辩论做了更多研究之后,我发现了这篇文章。就像我之前提到的那样,没有一个真正的正确或错误的答案。这取决于您的具体实施需求。但这些是使用GUID作为主键的一些非常有效的理由:

  

例如,存在称为“热点”的问题,其中表中的某些数据页面处于相对较高的货币争用下。基本上,发生的事情是桌子上的大部分流量(以及页面级锁定)发生在桌子的一小块区域,朝向末端。新记录将始终转到此热点,因为IDENTITY是一个序列号生成器。这些插入很麻烦,因为它们需要在添加到页面上的Exlusive页面锁定(热点)。由于页面锁定机制,这有效地将所有插入序列化到表中。另一方面,NewID()不受热点影响。使用NewID()函数生成的值仅对插入的短突发(其中函数被非常快速地调用,例如在多行插入期间)顺序,这导致插入的行在整个表的数据页中随机扩散最后的一切 - 从而消除了插入的热点。

     

此外,由于插入是随机分布的,因此页面拆分的可能性大大降低。虽然页面在这里拆分并且不太糟糕,但效果会很快加起来。使用IDENTITY,页面填充因子作为一种调整机制是非常无用的,并且可能也设置为100% - 行永远不会插入任何页面而是最后一页。使用NewID(),您实际上可以使用填充因子作为性能启用工具。您可以将填充因子设置为接近索引重建之间估计的卷增长的级别,然后使用dbcc reindex在非高峰时段安排重建。这有效地延迟了页面拆分的性能命中,直到非高峰时间。

     

如果您甚至,您可能需要为相关表启用复制 - 那么您也可以将PK作为uniqueidentifier并将guid字段标记为ROWGUIDCOL。复制将需要具有此属性的唯一值guid字段,如果不存在,则将添加一个。如果存在合适的字段,那么它将只使用那里的字段。

     

使用GUID进行PK的另一个巨大好处是,该值确实保证唯一 - 不仅仅是服务器生成的所有值,而是由 all <生成的所有值/ em>计算机 - 无论是您的数据库服务器,Web服务器,应用服务器还是客户端计算机。几乎所有现代语言都能够生成有效的guid - 在.NET中,您可以使用System.Guid.NewGuid。特别是在处理缓存的主 - 细节数据集时,这非常方便。您不必采用疯狂的临时键控方案,只是为了在提交之前将您的记录关联在一起。您只需从操作系统中为记录创建时的每个新记录的永久键值获取一个完全有效的新Guid。

     

http://forums.asp.net/t/264350.aspx

答案 1 :(得分:7)

主键有三个用途:

  • 表示列应该是唯一的
  • 表示列应为非空
  • 记录这是行
  • 的唯一标识符的意图

前两个可以用很多方式指定,就像你已经完成的那样。

第三个原因是好的:

  • 对于人类而言,他们可以很容易地看到你的意图
  • 对于计算机,因此可能比较或以其他方式处理您的表的程序可以在数据库中查询该表的主键。

主键不一定是自动递增的数字字段,所以我想说将guid列指定为主键是个好主意。

答案 2 :(得分:6)

刚刚跳进去,因为马特有点诱惑我。

您需要了解尽管默认情况下将聚簇索引放在表的主键上,但这两个概念是分开的,应该单独考虑。 CIX表示NCIX存储和引用数据的方式,而PK为每行提供唯一性以满足表的LOGICAL要求。

没有CIX的表只是一个堆。没有PK的表通常被认为是“不是表”。最好分别了解PK和CIX概念,以便在数据库设计中做出合理的决策。

罗布

答案 3 :(得分:3)

没有人回答实际问题:没有PK的桌子的优缺点是什么,也没有CLUSTERED索引。 在我看来,如果你优化了更快的插入(特别是增量大容量插入,例如当你将数据批量加载到非空表中时),这样的表:没有聚簇索引,没有约束,没有外键,没有默认值和在具有简单恢复模型的数据库中,没有主键是最好的。现在,如果您想查询此表(而不是完整地扫描它),您可能需要根据需要添加非群集的非唯一索引,但将它们保持在最低限度。

答案 4 :(得分:0)

我也一直听说即使你没有实际使用它,自动递增int对性能也有好处。

答案 5 :(得分:0)

主键不必是自动增量字段,在许多情况下,这只是意味着您使表结构变得复杂。

相反,主键应该是唯一标识元组的属性的最小集合(请注意,大多数DBMS将允许复合主键)。

在技术方面,它应该是元组中的每个其他字段完全在功能上依赖的字段。 (如果不是,您可能需要规范化)。

在实践中,性能问题可能意味着您合并表并使用递增字段,但我似乎回想起过早优化是邪恶的......

答案 6 :(得分:0)

由于您正在进行复制,因此您可以清楚地了解正确的身份。我会让你的GUID成为主键但非聚集,因为你不能使用newsequentialid。这让我觉得你是最好的课程。如果你没有把它作为PK但是在它上面放了一个唯一的索引,迟早会导致维护系统的人不理解FK关系正确引入错误。