SQL Server是否保证顺序插入标识列?

时间:2010-05-13 17:34:51

标签: sql-server sql-server-2008 identity-column

换句话说,以下“光标”方法是否有效:

  1. 从DB
  2. 检索行
  3. 保存返回记录中的最大ID以供日后使用,例如在LastMax
  4. 之后,"SELECT * FROM MyTable WHERE Id > {0}", LastMax
  5. 为了使其正常工作,我必须确保我在步骤1中未获得的每行的ID大于LastMax。这是保证,还是我可以遇到奇怪的竞争条件?

5 个答案:

答案 0 :(得分:17)

保证绝对在任何情况下都不可能获得可能小于或等于当前最大值的值?不,没有这样的保证。也就是说,这种情况可能发生的情况是有限的:

  1. 有人禁用标识插入并插入值。
  2. 有人重新标记了标识列。
  3. 有人更改增量值的符号(即代替+1,将其更改为-1)
  4. 假设没有这些情况,您就可以避免竞争条件造成下一个值低于现有值的情况。也就是说,不能保证行按照其身份值的顺序提交。例如:

    1. 打开一个事务,使用标识列插入到您的表中。假设它获得了值42。
    2. 在同一个表中插入并提交另一个值。假设它得到了值43。
    3. 在第一个交易提交之前,43存在但42则不存在。标识列只是保留一个值,它不是指示提交的顺序。

答案 1 :(得分:4)

我认为这可能会出错,具体取决于交易的持续时间 考虑以下事件序列:

  1. 交易A开始
  2. 事务A执行插入 - 这会在标识列
  3. 中创建一个新条目
  4. 交易B开始
  5. 事务B执行插入 - 这将在标识列
  6. 中创建一个新条目
  7. 交易B提交
  8. 您的代码执行其选择并查看第二个事务中的标识值
  9. 交易A提交 -
  10. 您的代码永远不会找到事务A插入的行。执行第6步时尚未提交。当执行下一个查询时,将无法找到它,因为它在标识列中的值低于查询所查找的值。

    如果您使用read-uncommitted隔离模式

    执行查询,则可能会有效

答案 2 :(得分:2)

身份将始终遵循定义身份的增量:

IDENTITY [(种子,增量)] http://msdn.microsoft.com/en-us/library/aa933196(SQL.80).aspx

可以是正面的也可以是负面的(你可以让它向前或向后递增)。如果您将身份设置为向前递增,则您的身份值将始终大于之前的值,但如果您回滚INSERT,则可能会遗漏一些。

是的,如果您将身份增量设置为正值,则循环逻辑将起作用。

答案 3 :(得分:1)

如果有人打开身份插入并手动将记录插入到跳过的ID(或者在某些情况下为负数),则唯一可能插入的记录可能会被插入。这是一种相当罕见的情况,通常只能由系统管理员完成。例如,可能会重新插入意外删除的记录。

答案 4 :(得分:0)

SQL Server唯一保证的是您的IDENTITY列将始终递增。

要考虑的事情:

  1. 如果发生INSERT失败,IDENTITY列无论如何都会增加;
  2. 如果发生回滚,IDENTITY列将不会返回其先前的值;
  3. 这解释了为什么SQL Server不保证顺序INDENTITY。

    有一种方法可以使用DBCC命令重置IDENTITY列。但在此之前,请考虑以下事项:

    1. 确保您的IDENTITY列未被任何其他表引用,因为您的外键无法使用它进行更新,因此面临巨大的麻烦;
    2. 您可以使用SET IDENTITY_INSERT ON/OFF指令,以便在插入行时手动指定IDENTITY(永远不要忘记将其打开)。
    3. IDENTITY列是DBRM中永远不会更改的最重要元素之一。

      以下是一个可以帮助您的链接:Understanding IDENTITY columns

        

      编辑:您似乎要做的事情应该起作用,因为LastMax的IDENTITY列将始终为每个INSERTed行递增。所以:

           
          
      1. 从数据表中选择行;
      2.   
      3. 保存LastMax状态;
      4.   
      5. 选择Id>行LastMax。
      6.         

        3)只会选择IDENTITY列大于LastMax的行,因此在保存LastMax后插入。