什么原因*不*使用GUID作为主键?

时间:2010-06-16 04:44:58

标签: sql database-design relational-database

每当我设计一个数据库时,我会自动为每个表启动一个自动生成GUID主键(除了查找表)

我知道我永远不会因重复的密钥,合并表格等而失眠。对我来说,哲学上任何特定记录在所有域中都应该是唯一的,并且这种唯一性应该以一致的方式表示。桌到桌。

我意识到它永远不会是最高效的选择,但是把表现放在一边,我想知道是否有反对这种做法的哲学论据?

根据回复,让我澄清一下:

我在谈论一直使用GUID代理键作为主键 - 无论是否以及如何在表上设计任何自然键或顺序键。这些是我的假设:

  1. 基于自然键的数据完整性可以设计,但不能设想。
  2. 主键的功能是参照完整性,与性能,顺序或数据无关。

8 个答案:

答案 0 :(得分:16)

GUID似乎是您主键的自然选择 - 如果您真的必须,您可能会争辩将其用于表的PRIMARY KEY。

我强烈建议不要使用GUID列作为群集密钥,默认情况下SQL Server会这样做,除非您明确告诉它不要。这样做的主要原因确实是性能,它会让你感到困惑......(它会信任我 - 只是时间问题) - 还浪费资源(SQL Server中的磁盘空间和RAM)机器)这真的没必要。

你真的需要分开两个问题:

1)主键是一个逻辑结构 - 唯一且可靠地标识表中每一行的候选键之一。这可以是任何东西,真的 - 一个INT,一个GUID,一个字符串 - 选择对你的场景最有意义的东西。

2)集群密钥(在表上定义“聚集索引”的一列或多列) - 这是物理存储相关的东西,在这里,一个小的,稳定的,不断增加的数据类型是您的最佳选择 - INT或BIGINT作为您的默认选项。

默认情况下,SQL Server表上的主键也用作群集键 - 但这不一定是这样!我个人看到将以前基于GUID的主/群集密钥分解为两个单独的密钥 - GUID上的主(逻辑)密钥和单独的INT IDENTITY上的群集(排序)密钥(1, 1)专栏。

作为Kimberly Tripp - 索引女王 - 以及其他人已多次声明 - GUID作为聚类键不是最佳的,因为由于其随机性,它将导致大量页面和索引碎片并且通常表现不佳。

是的,我知道 - 在SQL Server 2005及更高版本中有newsequentialid() - 但即使这样也不是真正完全顺序的,因此也会遇到与GUID相同的问题 - 只是不那么显着。< / p>

然后还有另一个需要考虑的问题:表格上的聚类键也会被添加到表格中每个非聚集索引的每个条目上 - 因此你真的想确保它尽可能小。通常,对于绝大多数表来说,具有2亿行的INT应该足够 - 并且与作为群集密钥的GUID相比,您可以在磁盘和服务器内存中节省数百兆的存储空间。

快速计算 - 使用INT与GUID作为主要和群集密钥:

  • 具有1'000'000行的基表(3.8 MB对15.26 MB)
  • 6个非聚簇索引(22.89 MB vs. 91.55 MB)

TOTAL:25 MB vs. 106 MB - 这只是在一张桌子上!

更多值得思考的东西 - 金佰利特里普的优秀作品 - 阅读,再读一遍,消化它!这是SQL Server索引福音,真的。

马克

答案 1 :(得分:14)

杰夫阿特伍德非常详细地谈到这一点:
http://www.codinghorror.com/blog/2007/03/primary-keys-ids-versus-guids.html

指导优点:
每个表,每个数据库,每个服务器都是唯一的 允许轻松合并来自不同数据库的记录 允许在多个服务器之间轻松分发数据库 您可以在任何地方生成ID,而不必往返数据库 大多数复制方案无论如何都需要GUID列

Guid Cons:
它比传统的4字节索引值大4倍;如果你不小心,这可能会产生严重的性能和存储影响 调试很麻烦(其中userid ='{BAE7DF4-DDF-3RG-5TY3E3RF456AS10}')
生成的GUID应该是部分顺序的以获得最佳性能(例如,SQL 2005上的newsequentialid())并允许使用聚簇索引

答案 2 :(得分:4)

添加到ewwwn:

赞成

  • 这使得开发人员几乎不可能“意外地”将代理键暴露给用户(与几乎所有时间都发生的整数不同)。
  • 使合并数据库比处理标识列简单几个数量级。

缺点

  • 胖。它更胖的真正问题是它每页占用更多空间,索引中的空间更大,使它们更慢。 Guids的额外存储空间在当今世界坦率地说无关紧要。
  • 您必须小心如何创建新值。真正的随机值不能很好地指数。你被迫使用COMB guid或一些为guid添加顺序元素的变体。

答案 3 :(得分:4)

您仍然可以实现每个表的自然键,不是吗? - 仅GUID键显然不会阻止重复数据,冗余和随之而来的数据完整性丢失。

假设您确实强制执行其他密钥,那么无异常地向每个表添加GUID可能只会增加不必要的复杂性和开销。它实际上并不能更容易地合并不同表中的数据,因为您仍然必须修改/删除表的其他键。我建议你应该根据具体情况评估GUID代理的使用。对每个表都有一个统一规则是没有必要或没有帮助的,因为每个表都会模拟不同的东西。

答案 4 :(得分:3)

简单回答:它不是关系型的。

记录(由GUID定义)可能是唯一的,但是没有任何关联的属性可以说是唯一的记录。

使用GUID(或任何纯代理键)与声明平面文件为关系不再具有关系性,因为每个记录都可以通过其行号识别。

答案 5 :(得分:1)

一个潜在的重要原因,但通常没有想到的是,您将来可能必须提供与Oracle数据库的兼容性。

由于Oracle没有uniqueid列数据类型,当两个不同的数据库中有相同主键的两种不同数据类型时,尤其是涉及ORM时,可能会导致一些噩梦。 p>

答案 6 :(得分:1)

我想知道为什么没有标准的“miniGUID”类型?似乎在GUID上执行合适的散列应该产生64位数,这在任何没有十亿或更多东西的宇宙中具有重复的重复概率。由于使用大多数GUID / miniGUID标识符的宇宙将永远不会超过一百万,甚至十亿,我认为一个较小的8字节miniGuid将非常有用。

当然,这不会表明它应该被用作聚集索引;这会严重影响性能。尽管如此,一个8字节的miniGUID只会浪费完整GUID空间的三分之一(与4字节索引相比)。

答案 7 :(得分:0)

我可以看到给定应用程序或企业自己的标识符是唯一的,并且在所有自己的域中以一致的方式表示(即因为它们可能跨越多个数据库)但GUID对于这些目的来说是过度的。我猜它们很受欢迎,因为它们是开箱即用的,设计和实现“企业密钥”需要时间和精力。设计人工识别器时的规则是尽可能简单但不简单。 IDENTITY太简单了,GUID不够简单。

存在于应用程序/企业之外的实体通常具有自己的标识符(例如,汽车具有VIN,书籍具有ISBN等)由外部可信源维护,并且在这种情况下GUID不添加任何内容。所以我想我在这里得到的哲学论点是,在每个表上使用一个人工标识符是不必要的。