SQL标识列不合时宜

时间:2009-01-09 14:05:41

标签: sql-server-2005

我们有一组数据库,其中一个表定义了一个Identity列作为主键。当这些子集被复制到其他服务器时,会创建一个种子系统,以便它们永远不会发生冲突。该系统是使用增量为50的起始种子。

通过这种方式,DB1上的表将生成30001,30051等,其中Database2将生成30002,30052等。

我正在考虑将另一个数据库添加到这个系统中(它被拆分用于扩展/加载目的)并且发现身份在一个或两个数据库上已经不同步 - 即数据库3应该有数字结束在3,不再了。根据表格设计,播种和增量仍然是正确的。

我显然不得不以某种方式解决这个问题(可能是通过设置一个较高的初始值),但是有人能告诉我是什么会导致它们像这样失去同步吗?从DB上的查询我可以看到序列如下:32403,32453,32456,32474,32524,32574并且自从它出错以来一直以50的增量继续。

据我所知,没有批量插入或DTS或类似内容将新数据放入这些表中。

第二个(奖金)问题 - 如何重置身份以使其恢复到我想要的实际状态!

编辑:

我知道设计原则上有点松懈 - 我没有要求批评它,我只是想知道它是如何不同步的。我继承了这个系统并将列更改为GUID - 毫无疑问是最好的理论解决方案 - 可能不会发生。当负载过大(目前几百GB)时,系统从单个DB演变为多个DB。此表中的每个ID都将在许多其他地方引用 - 有时每个数十万次(每个项目乘以约40,000)。更新所有这些将不会发生; - )

6 个答案:

答案 0 :(得分:2)

复制= GUID列。

将下一个ID的值设置为1000:

DBCC CHECKIDENT (orders, RESEED, 999)

答案 1 :(得分:2)

如果您想要将主键实际用于某些有意义的目的而不是唯一地标识表中的行,那么它不是标识列,您需要以其他显式方式为它们分配。

如果要合并多个表中的行,则违反了Identity的意图,即一个表。 (GUID列将使用足够独特的值来解决此问题。但您仍然无法将有意义的目的归咎于它们。)

答案 2 :(得分:1)

也许有人用过:

SET IDENTITY INSERT {tablename} ON

INSERT INTO {tablename} (ID, ...)
VALUES(32456, ....)

SET IDENTITY INSERT {tablename} OFF

或许他们使用DBCC CHECKIDENT来改变身份。在任何情况下,您都可以使用它来设置它。

答案 3 :(得分:1)

依靠这种身份策略风险太大,因为它(显然)可能会失去同步并破坏一切。

通过复制,您确实需要使用GUID识别您的数据。您可能更容易将数据迁移到使用PK的GUID的模式,而不是试图破解IDENTITY问题。

答案 4 :(得分:0)

直接解决您的问题,

  1. 为什么它不同步可能有趣的讨论,但你可以从答案中得出的唯一结果是将来防止它;这是一个糟糕的行动方案。除非你处理有致命缺陷的设计,否则你将继续遇到这些和更大的问题。

  2. 如何正确设置现有值也是(恕我直言)一个无效的问题,因为你需要做的事情不是设置正确的值 - 它不会解决你的问题。

  3. 这不是为了贬低你,而是以我能想到的最佳方式帮助你。改变设计不是短期和长期的工作。不改变设计是失败的途径。

答案 5 :(得分:0)

这并没有真正回答你的核心问题,但解决这个问题的一种可能性就是切换到hi_lo算法。它不需要将列更改为int。所以它不应该像改变guid一样多。

nhibernate ORM使用了Hi_lo,但是我找不到很多关于它的文档。

基本上Hi_lo的工作方式是你有一个中心位置,你可以跟踪你的hi值。 1个数据库中的1个表,您的插入应用程序的每个实例都可以看到。那么你需要有一种服务(对象,web服务,等等),其生命周期比单个实体插入更长。此服务启动时将转到hi表,获取当前值,然后递增该表中的值。使用读提交锁执行此操作,以便您不会遇到与该服务的其他实例的任何并发问题。现在,您将使用新服务获取下一个id值。它在内部从数据库获得的数字开始,当它传递该值时,增加1.跟踪当前值和允许传递的“范围”。一个简单的例子就是这样。

  1. 服务1从db中的“hi_value”表中获取100。递增db值200.
  2. 服务1获取新ID的请求。传出100。
  3. 该服务的另一个实例,服务2(另一个线程,另一个中间层工作者机器等)旋转,从数据库中获取200,将db增加到300。
  4. 服务2获取新ID的请求。传出200。
  5. 服务1获取新ID的请求。传了101。 如果其中任何一个在死亡之前传递超过100,那么它们将返回到数据库,并获得当前值并递增并重新开始。显然这有一些艺术。你的范围应该有多大等等。
  6. 一个非常简单的变体就是你的一个db中的一个表只包含“nextId”值。基本上手动复制oracle的序列概念。