到目前为止,我一直使用C#的“Guid = Guid.NewGuid();”方法生成一个唯一ID,并将其存储为某些SQL Server数据库表中的ID字段,通过Linq to SQL进行操作。
有人告诉我,出于索引的原因,使用GUID是不好的,而应该使用自增长的Long。那么,使用Long会加速我的数据库事务吗?如果是这样,我该如何生成类型为Long的唯一ID呢?
谢谢!
到目前为止,我一直使用C#的“Guid = Guid.NewGuid();”方法生成一个唯一ID,并将其存储为某些SQL Server数据库表中的ID字段,通过Linq to SQL进行操作。
有人告诉我,出于索引的原因,使用GUID是不好的,而应该使用自增长的Long。那么,使用Long会加速我的数据库事务吗?如果是这样,我该如何生成类型为Long的唯一ID呢?
谢谢!
两种方法都有优缺点,主要取决于使用方式。
如果您需要能够在多个数据库中使用的标识符,则需要GUID。Long(手动为每个数据库分配不同的种子/增量)有一些技巧,但这并不适用于大规模应用。
就索引而言,如果索引是聚集的(默认情况下主键是聚集的,但可以修改表),则Long将提供更好的插入性能,因为表在每次插入后不需要重新组织。
然而,在同时插入方面,Long(identity)列比GUID要慢 - 身份列生成需要一系列独占锁来确保只有一行获得下一个顺序号。在许多用户不断插入许多行的环境中,这可能会影响性能。在这种情况下,GUID生成速度更快。
存储方面,GUID占用的空间是Long的两倍(8字节对16字节)。然而,如果8字节会在行的总体大小上产生明显差异,并且从磁盘中提取的叶子数目因此减少,则取决于您的行的总体大小。
"索引女王" - Kim Tripp - 在她的索引博客文章中基本上已经说得很清楚了:
基本上,她的最佳实践是:最佳聚集键应该是:
GUID违反了"小"和"递增"原则,因此不是最佳选择。
此外:所有的聚簇键将被添加到每个非聚簇索引中的每个条目中(作为查找数据库记录的方式),因此您希望尽可能地使它们更小(INT = 4字节 vs. GUID = 16字节)。如果您有数亿行和多个非聚簇索引,选择 INT 或 BIGINT 而不是 GUID 可以产生重大差异 - 即使仅在空间上。
Marc
INT IDENTITY
或BIGINT IDENTITY
作为我的替代主键。 - marc_sIDENTITY
提供递增的值,这些值通过设计保证是唯一的 - 只要你让它们保持不变,不要去修改标识列... - marc_s一个长整型(在 SQL Server 中为 big int)占用 8 个字节,而 GUID 占用 16 个字节,因此当进行查找时,使用长整型可以减少 SQL Server 需要比较的字节数一半。
在数据库中创建字段时,请使用 IDENTITY(1,1) 生成长整型。
因此,可以使用 create table 或 alter table 命令来实现:
Field_NAME BIGINT NOT NULL PRIMARY KEY IDENTITY(1,1)
查看评论以发布Linq到SQL
你可以整天讨论GUID或identity。我更喜欢数据库使用identity生成唯一值。如果你从多个数据库合并数据,添加另一列(用于标识源数据库,可能是tinyint或smallint),并形成一个组合主键。
如果你选择使用identity,请确保根据预期生成的键数选择正确的数据类型:
bigint - 8 Bytes - max positive value: 9,223,372,036,854,775,807
int - 4 Bytes - max positive value: 2,147,483,647
当需要考虑到多个数据库的导入/导出时,请使用GUID。与指定IDENTITY属性的列相比,使用GUID在处理具有多个子关系的数据集时通常更容易。这是因为您可以在代码中以断开状态随机生成GUID,然后一次性提交所有更改。当GUID正确生成时,它们很难被偶然复制。对于标识列,您通常必须先插入父行并查询其新标识,然后再添加子数据。然后,您必须使用新的父标识更新所有子记录,然后将它们提交到数据库。孙子及以下的情况也是如此。这会积累很多看似不必要和乏味的工作。您可以通过不指定IDENTITY来生成类似于GUID的随机整数,但随着时间的推移,碰撞的几率会大大增加。(Guid.NewGuid()类似于随机Int128-尚不存在)。
我使用Byte(TinyInt),Int16(SmallInt),Int32 / UInt16(Int),Int64 / UInt32(BigInt)用于小型查找列表或不在多个数据库之间复制的数据(权限,应用程序配置,颜色名称等)。
我认为,无论您使用GUID还是长整型,索引查询所需的时间都是相同的。通常,表中有其他字段被索引,这些字段比128位更大(例如用户表中的用户名)。 GUID和整数之间的区别在于内存中索引的大小以及填充和重建索引的时间。大多数数据库事务通常是读取操作,写入操作很少。首先专注于优化从数据库中读取数据,因为它们通常由未经过适当优化的联接表、不正确的分页或缺少索引组成。
与任何事物一样,最好的方法是证明自己的观点。创建一个具有两个表的测试数据库。一个使用整数/长整型作为主键,另一个使用GUID。每个表都填充N百万行。监视每个表在CRUD操作(创建、读取、更新、删除)期间的性能。您可能会发现它确实会影响性能,但是影响微不足道。
服务器通常在没有调试环境和其他占用CPU、内存和硬盘I/O(特别是RAID)的应用程序的情况下运行。开发环境只能给您提供性能的大致概念。