关于sql server:没有主键的表

关于sql server:没有主键的表

Tables with no Primary Key

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

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

我的数据库是跨一堆服务器进行合并复制的,所以我避开了Identity int列,因为它们有点麻烦,无法正确进行复制。

你怎么看?表应该有主键吗?或者,如果没有明智的索引来建立索引,可以没有任何聚集索引吗?


在处理索引时,您必须确定表将用于什么。如果您主要是每秒插入1000行并且不执行任何查询,则聚集索引会影响性能。如果您每秒要执行1000个查询,那么没有索引将导致非常糟糕的性能。尝试调整查询/索引时,最好的办法是在SQL Server中使用查询计划分析器和SQL Profiler。这将向您显示正在遇到昂贵的表扫描或其他性能阻止程序的地方。

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

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

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

For example, there is an issue known as a"hotspot", where certain pages of data in a table are under relatively high currency contention. Basically, what happens is most of the traffic on a table (and hence page-level locks) occurs on a small area of the table, towards the end. New records will always go to this hotspot, because IDENTITY is a sequential number generator. These inserts are troublesome because they require Exlusive page lock on the page they are added to (the hotspot). This effectively serializes all inserts to a table thanks to the page locking mechanism. NewID() on the other hand does not suffer from hotspots. Values generated using the NewID() function are only sequential for short bursts of inserts (where the function is being called very quickly, such as during a multi-row insert), which causes the inserted rows to spread randomly throughout the table's data pages instead of all at the end - thus eliminating a hotspot from inserts.

Also, because the inserts are randomly distributed, the chance of page splits is greatly reduced. While a page split here and there isnt too bad, the effects do add up quickly. With IDENTITY, page Fill Factor is pretty useless as a tuning mechanism and might as well be set to 100% - rows will never be inserted in any page but the last one. With NewID(), you can actually make use of Fill Factor as a performance-enabling tool. You can set Fill Factor to a level that approximates estimated volume growth between index rebuilds, and then schedule the rebuilds during off-peak hours using dbcc reindex. This effectively delays the performance hits of page splits until off-peak times.

If you even think you might need to enable replication for the table in question - then you might as well make the PK a uniqueidentifier and flag the guid field as ROWGUIDCOL. Replication will require a uniquely valued guid field with this attribute, and it will add one if none exists. If a suitable field exists, then it will just use the one thats there.

Yet another huge benefit for using GUIDs for PKs is the fact that the value is indeed guaranteed unique - not just among all values generated by this server, but all values generated by all computers - whether it be your db server, web server, app server, or client machine. Pretty much every modern language has the capability of generating a valid guid now - in .NET you can use System.Guid.NewGuid. This is VERY handy when dealing with cached master-detail datasets in particular. You dont have to employ crazy temporary keying schemes just to relate your records together before they are committed. You just fetch a perfectly valid new Guid from the operating system for each new record's permanent key value at the time the record is created.

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


只是跳进去,因为马特有点吸引了我。

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

没有CIX的表只是一个堆。没有PK的表通常被认为是"非表"。最好分别了解PK和CIX概念,以便您可以在数据库设计中做出明智的决策。


主键用于三个目的:

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

正如您已经做过的那样,可以用很多方法指定前两个。

第三个原因是好的:

  • 对于人类,这样他们就可以轻松看到您的意图
  • 对于计算机,因此可以比较或以其他方式处理表的程序可以查询数据库以获取表的主键。

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


没有人回答实际问题:没有PK或没有聚集索引的表的优缺点是什么。
我认为,如果针对快速插入进行了优化(尤其是增量批量插入,例如,当您将数据批量加载到非空表中时),则该表将:没有聚集索引,没有约束,没有外键,没有默认值和在具有简单恢复模型的数据库中,没有主键是最好的。现在,如果您要查询该表(而不是对它进行整体扫描),则可能需要根据需要添加非聚集的非唯一索引,但将索引保持在最低水平。


由于您正在执行复制,因此您应该避免识别正确的身份。由于您不能使用newsequentialid,因此我会将您的GUID设为主键,但将其设为非集群。那使我震惊,这是你最好的选择。如果您不将其设置为PK,而是在其上添加唯一索引,则迟早会导致维护系统的人员无法正确理解FK关系,从而引入错误。


主键不必是自动递增的字段,在许多情况下,这仅意味着您正在使表结构复杂化。

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

用技术术语来说,元组中的每个其他字段都应该在功能上完全依赖该字段。 (如果不是,则可能需要规范化)。

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


我也总是听到有一个自动增量int对性能有好处,即使您实际上并不使用它也是如此。


推荐阅读