SQL Server - Guid VS.长

时间:2009-07-23 11:41:29

标签: c# sql sql-server guid long-integer

到目前为止,我一直在使用C#“Guid = Guid.NewGuid();”生成唯一ID的方法,该ID可以使用Linq to SQL存储在我的某些SQL Server数据库表中作为ID字段。 我被告知,出于索引的原因,使用GUID是一个坏主意,我应该使用自动递增Long。将使用长时间加速我的数据库事务?如果是这样,我该如何生成Long类型的唯一ID?

此致

7 个答案:

答案 0 :(得分:9)

两者都有利有弊,这完全取决于你如何使用它们。

如果您需要可以跨多个数据库工作的标识符,您需要GUID。 Long有一些技巧(手动为每个数据库分配不同的种子/增量),但这些技巧不能很好地扩展。

就索引而言,如果索引是聚簇的,Long将提供更好的插入性能(默认情况下,主键是聚簇的,但可以为您的表修改),因为每次执行后都不需要重新组织表插入

然而,就并发插入而言,Long(标识)列将比GUID慢 - 标识列生成需要一系列排它锁以确保只有一行获得下一个序列号。在许多用户一直插入许多行的环境中,这可能会影响性能。在这种情况下生成GUID更快。

存储方面,GUID占用了Long的两倍空间(8字节对16)。但是,如果8个字节对一个叶子中适合的记录数量产生显着差异,那么它取决于行的总体大小,从而在平均请求期间从磁盘中提取叶子的数量。

答案 1 :(得分:3)

一个long(sql server中的大型int)是8个字节,Guid是16个字节,所以你在查找时将sql server必须比较的字节数减半。

要生成long,请在数据库中创建字段时使用IDENTITY(1,1)。

所以使用create table或alter table:

Field_NAME BIGINT NOT NULL PRIMARY KEY IDENTITY(1,1)

请参阅将Linq发布到sql的评论

答案 2 :(得分:3)

答案 3 :(得分:3)

“索引女王” - Kim Tripp - 在她的索引博客文章中基本上都说明了这一点:

基本上,她的最佳实践是:最佳聚类键应该是:

  • 独特
  • 稳定(永不改变)
  • 不断增加

GUID违反了“小”和“不断增加”,因此不是最佳选择。

PLUS:所有的聚类键都将被添加到每个非聚集索引中的每个单独条目中(作为查找以实际查找数据库中的记录),因此您希望将它们设置为小到可能(INT = 4字节与GUID = 16字节)。如果你有数亿行和几个非聚集索引,那么在GUID上选择INT或BIGINT可以产生很大的不同 - 即使只是在空间方面。

马克

答案 4 :(得分:1)

你可以整天辩论GUID或身份。我更喜欢数据库生成带有标识的唯一值。如果合并来自多个数据库的数据,请添加另一列(以标识源数据库,可能是tinyint或smallint)并形成复合主键。

如果您确实使用了标识,请务必根据您将生成的预期密钥数选择正确的数据类型:

bigint - 8 Bytes - max positive value: 9,223,372,036,854,775,807  
int    - 4 Bytes - max positive value:             2,147,483,647

注意“预期键数”与行数不同。如果您主要添加并保留行,您可能会发现INT足够超过20亿个唯一键。我打赌你的桌子不会那么大。但是,如果你有一个高容量表,你不断添加和删除行,你的行数可能会很低,但你会快速通过键。您应该进行一些计算,以了解如何通过INT 20亿个密钥进行日志记录。如果它不会在短时间内使用它们,请使用INT,否则将键大小加倍并使用BIGINT。

答案 5 :(得分:1)

当您需要考虑导入/导出到多个数据库时,请使用guid。在处理多个子关系的数据集时,Guids通常比指定IDENTITY属性的列更容易使用。这是因为您可以在与数据库断开连接的状态下在代码中随机生成guid,然后一次提交所有更改。当guids正确生成时,它们很难偶然复制。对于标识列,您通常必须在添加子数据之前对父行进行初始插入并查询其新标识。然后,在将它们提交到数据库之前,必须使用新的父标识更新所有子记录。对孙子孙女来说同样如此,等等。它构建了许多看起来不必要和平凡的工作。您可以通过在没有IDENTITY规范的情况下使用随机整数来执行与Guids类似的操作,但随着时间的推移插入更多记录时,碰撞的可能性会大大增加。 (Guid.NewGuid()类似于随机的Int128 - 它还不存在。)

我将Byte(TinyInt),Int16(SmallInt),Int32 / UInt16(Int),Int64 / UInt32(BigInt)用于不更改的小型查找列表或不在多个数据库之间复制的数据。 (权限,应用程序配置,颜色名称等)

我想无论你使用的是guid还是long,索引都需要与查询一样长。表中通常还有其他字段的索引大于128位(例如用户表中的用户名)。 Guids和Integers之间的区别在于内存中索引的大小,以及填充和重建索引的时间。大多数数据库事务通常都在阅读。写作很少。首先要集中精力优化数据库的读取,因为它们通常由未正确优化的联接表,不正确的分页或缺少索引组成。

与任何事情一样,最好的办法是证明你的观点。使用两个表创建一个测试数据库。一个主键为long / long,另一个为guid。每个用N-Million行填充。在CRUD操作(创建,读取,更新,删除)期间监视每个的性能。您可能会发现它确实有性能损失,但无关紧要。

服务器通常在没有调试环境的盒子上运行,其他应用程序占用硬盘的CPU,内存和I / O(特别是使用RAID)。开发环境只能让您了解性能。

答案 6 :(得分:1)