4

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

问候,

4

7 回答 7

10

两者都有优点和缺点,这完全取决于您如何使用它们。

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

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

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

存储方面,GUID 占用的空间是 Long 的两倍(8 个字节对 16 个)。但是,这取决于行的整体大小,如果 8 个字节会在一个叶子中容纳多少记录产生显着差异,从而在平均请求期间从磁盘中提取的叶子数量有显着差异。

于 2009-07-23T12:07:14.800 回答
4

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

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

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

GUID 违反了“小”和“不断增加”的原则,因此不是最优的。

加:你所有的集群键将被添加到每一个非聚集索引中的每一个条目中(作为在数据库中实际查找记录的查找),因此你想让它们尽可能小(INT = 4 字节与 GUID = 16 字节)。如果您有数亿行和多个非聚集索引,则选择 INT 或 BIGINT 而不是 GUID 可能会产生重大影响——即使只是在空间方面。

马克

于 2009-07-23T13:52:08.737 回答
3

long(sql server 中的 big int)为 8 个字节,Guid 为 16 个字节,因此您将 sql server 在查找时必须比较的字节数减半。

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

所以要么使用创建表或更改表:

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

查看将 Linq 发布到 sql 的评论

于 2009-07-23T11:42:53.490 回答
3

看看这个

对标识列使用 uniqueidentifier(GUID) 还是 bigint 更好?

于 2009-07-23T11:50:19.000 回答
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

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

于 2009-07-23T13:32:16.560 回答
1

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

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

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

与任何事情一样,最好的办法就是证明你的观点。创建一个包含两个表的测试数据库。一个具有整数/长整数的主键,另一个具有 guid。用 N-Million 行填充每个。在 CRUD 操作(创建、读取、更新、删除)期间监控每个操作的性能。您可能会发现它确实有性能影响,但微不足道。

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

于 2009-07-24T21:23:55.867 回答
1

考虑从 .NET 应用程序创建顺序 GUID:

http://dotnet-snippets.de/dns/sequential-guid-SID998.aspx

Sequential Guid 相对于标准 Guid 有哪些性能改进?

于 2009-07-26T15:44:26.540 回答