Mat*_*ton 41 sql-server indexing
我有几个表,其唯一的唯一数据是uniqueidentifier(Guid)列.因为guid是非顺序的(并且它们是客户端生成的所以我不能使用newsequentialid()),所以我在这个ID字段上创建了一个非主要的非聚集索引,而不是给表一个聚簇的主要键.
我想知道这种方法的性能影响.我见过一些人建议表应该有一个自动递增("identity")int作为聚簇主键,即使它没有任何意义,因为这意味着数据库引擎本身可以快速使用该值查找一行而不必使用书签.
我的数据库是在一堆服务器上进行合并复制的,所以我已经避开了identity int列,因为它们在复制方面有点毛茸茸.
你的想法是什么?表应该有主键吗?或者,如果没有合理的列来索引那么,是否可以没有任何聚簇索引?
Jer*_*ark 33
处理索引时,您必须确定要用于表的内容.如果您主要是每秒插入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的另一个巨大好处是,该值确实是唯一的 - 不仅是该服务器生成的所有值,而且是所有计算机生成的所有值- 无论是您的数据库服务器,Web服务器,应用服务器或客户端机器.几乎所有现代语言都能够生成有效的guid - 在.NET中,您可以使用System.Guid.NewGuid.特别是在处理缓存的主 - 细节数据集时,这非常方便.您不必采用疯狂的临时键控方案,只是为了在提交之前将您的记录关联在一起.您只需从操作系统中为记录创建时的每个新记录的永久键值获取一个完全有效的新Guid.
主键有三个用途:
正如您已经完成的那样,前两个可以通过多种方式指定.
第三个原因是好的:
主键不必是自动递增的数字字段,因此我想说将guid列指定为主键是个好主意.
刚跳进来,因为马特的诱饵让我有点兴奋.
您需要了解尽管默认情况下将聚簇索引放在表的主键上,但这两个概念是分开的,应该单独考虑.CIX表示NCIX存储和引用数据的方式,而PK为每行提供唯一性以满足表的LOGICAL要求.
没有CIX的表只是一个堆.没有PK的表通常被认为是"不是表".最好分别了解PK和CIX概念,以便在数据库设计中做出明智的决策.
抢