主键 - 本机键,序列键还是GUID键?

时间:2009-07-21 00:27:17

标签: orm primary-key database-agnostic design-decisions

在阅读thisthis然后阅读this(讽刺地引用其他两个)时,我发现自己想知道这个主题的讨论有多大?我是一个SQL Server人,因此我倾向于使用以int形式自动生成的Identity。但是,当我知道服务器和服务器之间需要某种形式的复制或客户端和服务器之间的同步时,我倾向于使用GUID作为我的密钥。

问题:我是否应该始终在所有表中使用GUID作为主键,以防万一我可能需要这种可扩展性?这是否使我的架构更灵活,因为它可以随时在平台之间迁移?这是否有助于我通过不嵌入平台特定功能来保持ORM的灵活性(无论风味如何)?

对策:

@David Archer:根据你的评论我更新了我的帖子,不说“自然键”。你的自然密钥定义为such是正确的。谢谢你的纠正。

6 个答案:

答案 0 :(得分:4)

我倾向于更喜欢应用程序生成的主键,通常使用由NHibernate实现的lo / hi算法(当我在项目中使用它时)。否则,顺序GUID也可以正常工作。这不仅仅是我的建议,而是severalwho have一直在做这个整个发展的事情比我长得多。

我在使用数据库生成的主键时遇到的问题是,在将数据库保存到数据库之前,必须先访问数据库以获取这些标识值,而不是设置所有内容。由于这一事实,它通常会破坏NHibernate中的工作单元模式。如果你没有在你的应用程序中使用UoW模式,那么显然这个缺点不适用。

如果您正在为PK使用GUID,那么您肯定希望使用顺序GUID来消除索引碎片。这也为您提供了另一张海报所提到的“粗略排序顺序”,尽管我通常有一个DateInserted列或者类似于这些类型的东西。

加入GUID列has been shown,与4字节整数相比,性能开销相当小,我敢说,对于非大型数据集,性能差异很小。

自然键是魔鬼的产物。 :)

答案 1 :(得分:3)

您可能不应该使用原始GUID作为主键。这样做会导致数据严重分散。 SQL Server有function为您提供“顺序指南”以帮助缓解此问题。深入讨论了这个主题here。另一个很好的讨论是here ......

  

这显示了碎片的数量   随机guids是非常重要的   (推荐“碎片化”   百分比“应该接近零   尽可能)。使用的页数   通过随机guid高出40%   每页上使用的空间量是   更少,因此光盘空间   要求会增加。

答案 2 :(得分:2)

除非你知道你真的需要它(即用于多系统同步等),否则我会避免主键的GUIDS。

在SQL Server复制领域,guid被添加到复制表中的行以实现唯一性,因此如果您有需要,可以在以后建立此设计。

关于碎片,还要考虑磁盘空间的成本。如果你将要在10,000行以下(在表中),这可能不是一个大问题,但如果你的系统必须支持超过10,000行(在表中),你会发现性能和磁盘存储成本(以及索引碎片)通过使用Big Ints(大整数)+身份(自动编号)可以更好地服务,它可以很好地扩展到音量。

我完全避免使用自然键 - 即使逻辑在其周围发生变化的风险也会使其too风险太大(例如,如果它们突然变得非常独特)。

答案 3 :(得分:2)

我支持大多数其他的回答者说你应该避免使用GUID作为SQL Server中的集群密钥 - 如果你真的想要,你可以将它们用作主键,但不要将表集中在它上面。

主键是唯一标识每一行的键的逻辑概念 - 这里,GUID可以有意义,因为它几乎可以保证是唯一的。

但是群集密钥是一个物理概念,它在物理上对表中的行进行排序,这里由于它们的随机特性,GUID非常适合。这将导致大量索引碎片,从而导致性能不佳,即使您一遍又一遍地重新组织索引(以及表数据)。

此外,由于聚集索引键被用作查找值以查找表中的行,因此它将被添加到表中每个非聚集索引的每个条目中,并且此处GUID(16字节)与INT(4字节)的大小发挥作用 - 为了跟踪查找值,您可能会浪费大量空间。

我所知道的主要/聚簇索引和GUID的最佳讨论是由SQL Tripp中的索引女王Kim Tripp撰写的几篇文章 - 检查出来!

她对聚集索引的最终要求是:小,稳定,独特,并且希望不断增加。 GUID违反了其中两个(小而且不断增加)。甚至SQL Server中的NEWSEQUENTIALGUID()函数生成的GUID也不是完全和真正的顺序 - 所以我也不会使用它们。

马克

答案 4 :(得分:1)

我被“自然键”改变或被复制而被烧毁的次数太多以至于不能考虑使用它们。我决定是否使用序列或GUID作为密钥取决于我是否希望阅读或说出其中一个。

答案 5 :(得分:1)

我对此没有多少经验,但使用GUID加入让我感到畏缩。 4个字节对36个似乎很icky。

但是我已经开始使用GUID作为公共标识符而不是标识字段本身。看一下上面的URL,1156712。如果由于某种原因SO必须与另一个类似的应用程序(比如SU)合并,这些问题id会碰撞一个或另一个必须改变它的URL搞乱任何硬编码链接和可能谷歌统计数据也是如此。然而,如果每个元素被公开识别的方式是通过使用GUID和内部联接使用int或bigint字段,那么你可以充分利用这两个领域。

使用这种方法合并仍然是可能的。如果发现冲突,则可以动态生成新的内部标识符,而不会中断应用程序的其余部分。