没有主键的表格
我有几个表,其唯一的唯一数据是唯一标识(Guid)列。 因为GUID是非顺序的(而且它们是客户端生成的,因此我不能使用newsequentialid()),所以我在这个ID字段上创build了一个非主要的非聚集索引,而不是给这些表聚集主键。
我想知道这种方法的性能影响是什么。 我曾经看到一些人build议,即使表没有任何意义,表也应该有一个自动递增(“identity”)int作为集群主键,因为这意味着数据库引擎本身可以快速使用该值查找一行,而不必使用书签。
我的数据库在一堆服务器上被合并复制,所以我已经避开了身份列,因为它们有点复杂。
你怎么看? 表格是否有主键? 或者没有任何聚集索引,如果没有明智的列索引这种方式?
处理索引时,必须确定要使用的表格。 如果你主要每秒插入1000行而不做任何查询,那么聚集索引对性能就是一个打击。 如果您每秒钟处理1000个查询,那么没有索引会导致非常糟糕的性能。 尝试调整查询/索引时最好的做法是使用SQL Server中的查询计划分析器和SQL事件探查器。 这会告诉你你在哪里运行昂贵的表扫描或其他性能障碍。
至于GUID和ID参数,你可以在网上find两个人发誓的人。 我总是被教导使用GUID,除非我有一个非常好的理由不要。 杰夫有一个很好的职位,谈论使用GUIDs的原因: http : //www.codinghorror.com/blog/archives/000817.html 。
与大多数与开发相关的东西,如果你想提高性能,没有一个单一的正确的答案。 这实际上取决于你想要完成什么以及你如何实施解决scheme。 唯一真正的答案是对性能指标再次进行testing,testing和testing,以确保达到目标。
[编辑] @Matt,在对GUID / ID辩论进行了更多的研究之后,我遇到了这个post。 就像我之前提到的那样,没有一个真正的对与错的答案。 这取决于你的具体实施需求。 但是这些是使用GUID作为主键的一些非常有效的理由:
例如,有一个被称为“热点”的问题,表中的某些数据页面处于较高的货币争用状态。 基本上,发生什么事情是大多数表上的stream量(因此页面级锁)发生在表的一个小区域,到最后。 新的logging总是会出现在这个热点上,因为IDENTITY是一个序号发生器。 这些插入是很麻烦的,因为它们需要在它们被添加到的页面(热点)上的Exlusive页面locking。 这有效地连续化所有插入到一个表感谢页面locking机制。 另一方面,NewID()不会受到热点的影响。 使用NewID()函数生成的值仅对于插入的短突发(其中函数被快速调用,例如在多行插入期间)是连续的,这导致插入的行在整个表的数据页中随机地传播在所有的结尾 – 从而消除插入热点。
而且,由于插入是随机分布的,页面拆分的机会大大减less。 虽然页面在这里和那里分裂并不是太糟糕,但是效果会快速加起来。 使用IDENTITY,页面填充因子作为一个调整机制是相当无用的,也可能被设置为100% – 行将永远不会被插入任何页面,但最后一个。 使用NewID(),您实际上可以使用填充因子作为性能支持工具。 您可以将填充因子设置为接近索引重build之间的估计增长量的级别,然后使用dbcc reindex在非高峰时段计划重build。 这有效地延迟了页面拆分的性能命中,直到非高峰时间。
如果你甚至认为你可能需要为有问题的表启用复制,那么你也可以让PK成为唯一标识符,并将GUID字段标记为ROWGUIDCOL。 复制将需要一个具有此属性的唯一值guid字段,如果不存在,它将添加一个。 如果存在一个合适的字段,那么它将使用那里的那个。
PK使用GUID的另一个巨大的好处是这个值确实是唯一的 – 不仅仅是在这个服务器产生的所有值中,而且是所有计算机产生的所有值 – 无论是你的数据库服务器,Web服务器,应用服务器或客户机。 几乎每一种现代语言都有能力生成一个有效的GUID – 在.NET中你可以使用System.Guid.NewGuid。 处理caching的主数据集时,这非常方便。 你不必采用疯狂的临时密钥scheme,只是在你的logging被提交之前把你的logging联系在一起。 在创buildlogging时,您只需从操作系统中为每个新logging的永久键值获取完全有效的新Guid。
主键有三个目的:
- 表示该列应该是唯一的
- 表明列应该是非空的
- logging这是行的唯一标识符的意图
前两个可以用很多方式指定,就像你已经完成的那样。
第三个原因是好的:
- 对于人类,所以他们可以很容易地看到你的意图
- 对于计算机,所以可能比较或以其他方式处理您的表的程序可以在数据库中查询表的主键。
一个主键不一定是一个自动递增的数字字段,所以我会说这是一个好主意,指定您的guid列作为主键。
只是跳进去,因为马特引诱了我一点。
你需要明白,尽pipe默认情况下聚集索引被放在表的主键上,但是这两个概念是分开的,应该分开考虑。 CIX表示数据被NCIX存储和引用的方式,而PK为每行提供唯一性以满足表的逻辑要求。
没有CIX的表只是一个堆。 没有PK的桌子通常被认为是“不是桌子”。 最好分别理解PK和CIX概念,以便在数据库devise中做出明智的决定。
抢
没有人回答真正的问题:什么是没有PK NOR CLUSTERED索引的表的优缺点。 在我看来,如果你优化更快的插入(特别是增量批量插入,例如当你将数据批量加载到非空表时),这样一个表:没有聚集索引,没有约束,没有外键,没有默认和在具有简单恢复模型的数据库中,没有主键是最好的。 现在,如果你想要查询这个表(而不是完整地扫描它),你可能需要添加一个非集群的非唯一索引,但要保持在最低限度。
主键不一定是自动增量字段,在许多情况下,这只意味着你正在复杂化你的表结构。
相反,主键应该是属性的最小集合(注意大多数DBMS将允许一个复合主键)唯一地标识一个元组。
用技术术语来说,应该是元组中所有其他领域在function上完全依赖的领域。 (如果不是,你可能需要正常化)。
在实践中,性能问题可能意味着你合并表,并使用增量字段,但我似乎回想起过早优化是邪恶的东西…
我也总是听说有一个自动递增的int对性能有好处,即使你没有真正使用它。
既然你正在做复制,你的正确身份就是要避开的东西。 我会让你的GUID成为一个主键但是非聚簇,因为你不能使用newsequentialid。 这使我成为你最好的课程。 如果你没有把它做成一个PK,而是给它一个唯一的索引,迟早会导致维护这个系统的人不能正确地引入错误的FK关系。