从int移到GUID作为主键
我将几个引用的表与整数主键一起使用。现在,我想将int更改为GUID,保留所有引用不变。最简单的方法是什么?
谢谢!
添加
我确实了解该过程,所以我需要更详细的建议,例如,如何填充新的GUID列。使用默认值newid()是正确的,但是对于已经存在的行呢?
解决方案
首先:亲爱的上帝,为什么?!?!?
其次,我们将必须首先将GUID列添加到所有表,然后根据int值填充它们。完成后,我们可以将GUID设置为主键/外键,然后删除int列。
要更新值,我们可以执行以下操作
- 在主键表中设置新的GUID
- 运行这个:
。
UPDATE foreignTable f SET f.guidCol = p.guidCol FROM primaryTable p WHERE p.intCol = f.intCol
是的,我和Glenn在一起...实际上,我在发布相同内容之前一直在犹豫,...。
为什么不希望将自动增量int主键与GUID分开?它更加灵活,我们只需将GUID列编入索引,以便在查询中获得良好的性能...
至于灵活性,我喜欢将id保留为autoincrement int,因为这样其他看似唯一且具有主键的有价值的项就可以更改。
灵活性的一个很好的例子是,如果我们使用用户名作为主键。即使它们是唯一的,也能够更改它们是很好的。如果用户使用电子邮件地址作为用户名怎么办?能够更改用户名并且不影响所有查询是一个很大的优势,我怀疑GUID可能也是如此。
我认为,我们必须手动进行。或者,我们可以为其编写一些实用程序。该方案应为:
- 将" int" PK / FK列与新的" guid"列重复。
- 为"引导" PK列生成新值。
- 用指定的值更新" guid" FK列中的值(我们可以通过" int" PK查找记录)。
- 用" int"个PK / FK列删除引用(关系)。
- 使用" guid" PK / FK列创建类似的引用(关系)。
- 删除" int" PK / FK列。
- 在主表中为guid值创建一个新列。使用uniqueidentifier数据类型,并使其不为null,默认值为newid(),以便将填充所有现有行。
- 在子表中创建新的uniqueidentifier列。
- 运行更新语句以使用exisitng int关系引用实体来建立公会关系。
- 删除原始的int列。
另外,由于Guid不像int标识列那样连续,因此请在数据/索引页中保留一些空间(指定fillfactor <100)。这意味着插入内容可以在数据范围内的任何位置,并且如果页面100%充满,将导致页面拆分。
这在实现分布式计算模型的系统中是无关紧要的。如果在我们将信息保留在系统中时要求系统知道主键,则使用由ONE处理程序维护的自动递增主键会降低系统速度。相反,我们需要一种类似于GUID生成器的机制来创建主键(请注意,主键的真正特征是其唯一性)。因此,我可以扩展多个服务,每个服务彼此独立地创建其主键。
我之前曾有这样做的可疑特权,基本上我要做的就是将整个该死的数据库导出为XML。接下来,我有一个Java应用程序,该应用程序使用java.util.Random的nextLong()函数将主键替换为其新的guid键。之后,我将整个内容重新导入到数据库中。
当然,当我第一次尝试将XML文件导入回来时,我忘记了关闭主键字段的自动编号功能,因此请从我的错误中吸取教训。我敢肯定,有更好的方法可以做到这一点,但这是一种快速而肮脏的方法……而且行之有效。如果我们想知道,该项目将扩大应用程序规模。
有趣的是,由于另一个问题,我需要做相反的事情……
如何在具有GUID主键和默认newsequentialid()的表上使用SQLBulkCopy?
这是一个很好的选择。对于我的一种应用程序,我从longs切换到UUID,我并不后悔。如果我们使用MS SQL Server,则它包含在标准中(我使用的是postgresql,它仅包含在8.3及更高版本的标准中)。
就像Glenn Slaven提到的那样,我们可以根据当前记录中的键来重新创建UUID。请注意,虽然它们并不是唯一的,但是这样可以很容易地保持关系的完整性。我们在移动后创建的新记录将是唯一的。
不要做!我们开始使用GUID,现在几乎完成了将INT转换为PK的工作。我们保留了GUID以便进行日志记录(以及某些表,例如"可协商的关系完整性";)),但是使用int的速度显着提高。
请注意,只有当表的行数达到数百万时,这才真正变得明显。
到目前为止,我们最大的愚蠢是使用NEWID()作为我们(顺序)日志表的PK,当我们意识到自己的错误时,头晕目眩。