从整数转换为GUID作为主键

9
我使用了几个带有整数主键的引用表。现在我想将int更改为GUID,同时保留所有引用关系。最简单的方法是什么?
谢谢! 补充 我大致了解这个过程,所以我需要更详细的建议,例如如何填写新的GUID列。使用默认值newid()是正确的,但对于已经存在的行呢?

作为对未来读者的警告:仅在经过_慎重_考虑后将唯一标识符(GUID)用作主键,往往不是一个好主意。 - DdW
7个回答

13
  • 在主表中创建一个新的guid列。使用uniqueidentifier数据类型,将其设为非空且默认值为newid(),以便为所有现有行填充值。
  • 在子表中创建新的uniqueidentifier列。
  • 运行更新语句来建立guid关系,使用现有的int关系引用实体。
  • 删除原始的int列。

此外,在数据/索引页中留出一些空间(指定fillfactor < 100),因为guid不像int identity列那样连续。这意味着插入可以出现在数据范围内的任何位置,并且如果您的页面100%满,则会导致页面拆分。


6

首先:天哪,为什么会这样?!?!

其次,你需要先在所有的表中添加 GUID 列,并基于 int 值填充它们。完成后,你可以将 GUID 设置为主键 / 外键,然后删除 int 列。

要更新值,你需要执行以下操作:

  1. 在主键表中设置新的 GUID
  2. 运行以下命令:

.

UPDATE foreignTable f
SET f.guidCol = p.guidCol
FROM primaryTable p
WHERE p.intCol = f.intCol

我同意Glenn的观点。对于主键,我会坚持使用整数。如果需要更多记录,请使用bigints。如果需要全局标识符,请使用类似URI的东西作为辅助键,并坚持使用整数作为主键。 - Mark Cidade
但是如何在主键表中设置新的GUID? - Alexander Prokofyev
2 Alexander Prokofyev: 将所有“guid” PK列的默认子句设置为“newid()”。2 marxidad:如果需要在另一个环境(例如winforms应用程序)中创建级联记录,则使用Guid而不是(大)int非常有用。 - TcKs
2个TcKs:但是旧记录的GUID为空怎么办? - Alexander Prokofyev
UPDATE some_table SET some_guid_column = newid() WHERE some_guid_column IS NULL - TcKs
Glenn,有些情况下你需要一个唯一标识符作为主键,例如:Microsoft Sync Framework或任何需要将主数据库与多个客户端数据库同步的项目。顺便说一句:这就是我来到这个SO问题的原因,我有一个带有int作为主键的主数据库,但现在,我需要部署多个客户端数据库并将它们与主数据库同步。 - Alexandre

3
这在实现分布式计算模型的系统中非常相关。如果系统在持久化信息时需要知道主键,由一个处理程序维护的自增主键将会减慢系统速度。相反,您需要像GUID生成器这样的机制来创建主键(请记住,主键的真正特征是其唯一性)。因此,我可以扩展多个服务,每个服务都独立地创建其自己的主键。
我曾经有过怀疑的特权去做这件事,基本上我所要做的就是将整个数据库导出为XML。接下来,我使用java.util.Random的nextLong()函数编写了一个Java应用程序,以新的guid键替换主键。之后,我将整个东西重新导入到数据库中。
当然,第一次尝试将XML文件导入回去时,我忘记关闭主键字段的自动编号功能,所以请从我的错误中吸取教训。我相信有更好的方法来完成这项工作,但这是一种快速而肮脏的方式……而且它有效。如果你想知道,这个项目的目的是使应用程序能够扩展。

2

是的,我同意Glenn的观点...在他发布之前我也犹豫了一下是否要发表同样的内容...

为什么你不想要一个自动递增的int主键和GUID分开呢?这样更加灵活,而且你可以对GUID列进行索引,这样查询性能会很好...


至于灵活性,我喜欢把我的id作为自动递增的int,因为其他看起来唯一且应该成为主键的内容可以改变。

灵活性的一个很好的例子是如果你使用用户名作为主键。即使它们是唯一的,能够更改它们也是好的。如果用户将电子邮件地址用作用户名怎么办?能够更改用户名并且不影响所有查询是一个大的优点,我认为对于你的GUID也可能是这样的。


我在使用特殊值作为PK时有最好的体验。因为这样,如果更改记录中的任何值(例如:因为用户打了错字),就不会出现问题。 - TcKs

0

我认为你必须手动完成它。或者你可以编写一些实用程序来完成它。场景应该是:

  • 使用新的“guid”列复制“int” PK/FK列。
  • 为“guid” PK列生成新值。
  • 使用指定的值更新“guid” FK列中的值(通过“int” PK查找记录)。
  • 删除与“int” PK/FK列的引用(关系)。
  • 使用“guid” PK/FK列创建类似的引用(关系)。
  • 删除“int” PK/FK列。

0

这是一个非常好的选择。我在我的一个应用程序中从longs切换到UUID,我没有后悔。如果您使用MS SQL Server,则已包含在标准中(我使用postgresql,仅从8.3开始包含在标准中)。

Glenn Slaven所提到的,您可以从当前记录中的键重新创建UUID。请注意,它们将不是唯一的,但这样可以轻松保持关系完整。移动后创建的新记录将是唯一的。


0

不要这样做!我们最初使用GUID,现在我们几乎完成了将其移动到INT作为PK;我们保留GUID用于记录目的(以及某些表格的“可协商关系完整性”;),但是使用int的速度提高是惊人的。

当表行数超过百万时,这才真正显现出来。

我们最大的愚蠢是将NEWID()用作(顺序)日志表的PK - 当我们意识到错误时,我们非常后悔。


3
也许是错误的索引?你的guid主键上没有使用聚集索引,而是使用了一些更好的外键索引。这往往是一个错误。 - TcKs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接