是否将一个INT添加到一个表,其中PRIMARY KEY是一个UNIQUEIDENTIFIER,用于JOIN表的目的值?

时间:2011-08-01 09:08:03

标签: sql-server performance join indexing uniqueidentifier

我的SQL Server 2008数据库中有两个表:Users和Items

tblUser 
--------------------------
UserID    uniqueidentifier
Name      nvarchar(50)
etc..


tblItem 
--------------------------
ItemID    uniqueidentifier
ItemName      nvarchar(50)
etc..

tlmUserUserItem
----------------------------
ItemID      uniqueidentifier
UserID_A    uniqueidentifier
UserID_B    uniqueidentifier

我想在多对多的连接表中将这些连接在一起,这将会变得非常大(可能超过10亿行,因为应用程序逻辑需要统计数据超过共享用户 - >项目连接)

需要在UserID_A和UserID_B列上对连接表建立索引,因为查找是基于用户对其对等方的。

我的问题是:

是否值得在用户表上添加自动增量INT以用作非主键,然后在连接表中使用它?所以User表看起来像:

tblUser 
---------------------------------
UserID         uniqueidentifier
Name           nvarchar(50)
UserIDJoinKey  int  identity(1,1)
etc..

这样做,可以更快地执行以下操作:

declare @ID int
select * from tblJoin where UserIDJoinKey_A = @ID or UserIDJoinKey_B = @ID

当连接表如下所示:

tlmUserUserItem
-----------------------------------
ItemID             uniqueidentifier
UserIDJoinKey_A    int
UserIDJoinKey_B    int

而不是:

tlmUserUserItem
----------------------------
ItemID      uniqueidentifier
UserID_A    uniqueidentifier
UserID_B    uniqueidentifier

提前致谢。

4 个答案:

答案 0 :(得分:1)

如果您对使用uniqueidentifier的表的连接操作遇到性能问题,请首先检查索引碎片。具有uniqueidentifier聚簇索引的热表往往会快速碎片化。有关如何在http://msdn.microsoft.com/en-us/library/ms189858.aspx

执行此操作的详细信息

如果您能够将聚集索引移动到新的int列并重写查询以使用新的int列而不是旧的uniqueidentifier,那么最大的好处就是可以降低碎片率。这有助于避免在对表进行大量写入后减慢查询速度。

在大多数情况下,您不会注意到在uniqueidentifier列上处理连接操作的时间与在MSSQL 2008中处理int的时间差别很大 - 假设所有其他事物(包括碎片)都相同。

答案 1 :(得分:1)

我可能会误解某些内容,但您希望在每条记录中添加标识和唯一标识符?当我看到你使用GUID时,我认为当用户上线时会有合并的离线功能,或者存在选择GUID的一些无关的原因。这个原因应该阻碍您在每个项目上正确实现标识列。

如果您没有特定原因需要使用guid而不是身份,我会说将GUID全部废弃。它使您的表,索引和减慢连接变得臃肿。如果我误会请告诉我,我道歉!

答案 2 :(得分:0)

要找出什么是最佳解决方案,首先要有一些索引理论。 SQL Server将其聚簇索引数据存储在B + Tree数据页中,每页允许大约8K数据。 当您知道每个密钥uniqueidentifier为16个字节且每个密钥int为4个字节时,这意味着每个索引页的密钥将增加4倍int

要快速加入int列,您很可能必须将其作为聚集索引。请注意,在这样一个大型表上使用附加索引可能会对insert语句造成不必要的性能损失,因为有更多信息要写入磁盘。

这一切都归结为对两种解决方案进行基准测试并选择最适合您的解决方案。如果表读得更重,则int列将提供更好的性能。

答案 3 :(得分:0)

@MikeM,

我个人总是会选择一个uniqueidentifier而不是int作为表的主键。但是我会使用NEWSEQUENTIALID()而不是NEWGUID()来确保索引碎片更少。

我做出这个选择的原因很简单:

整数太容易混淆,并且在具有多个外键的表上,“意外地”将值放入错误字段的可能性太高。您永远不会看到问题,因为所有标识列都以1的种子开始,因此大多数表往往在每个表中都有匹配的整数值。通过使用uniqueidentifier,我绝对保证具有外键的列的所有实例都是正确的,因为它引用的表是唯一能够具有该唯一标识符的表。

更重要的是......在代码中,你的参数都将是int,这再次打开你可能会意外地将错误的值放入错误的参数中,你永远不会知道任何不同。通过使用唯一标识符,您再次保证正确的引用。

尝试追踪由于交叉发布的整数而导致的错误是阴险的,最糟糕的是你永远不会知道问题已经发生,直到为时已晚并且数据已经太过腐败而你永远不会混乱。所需要的只是一个交叉匹配的整数字段,您可能会创建数百万个不一致的行,在您只是“碰巧”尝试插入引用表中不存在的值之前,您都不会知道这些行。到那时可能为时已晚。