在 SQL Server 2017 中使用标识列间隙

Posted

技术标签:

【中文标题】在 SQL Server 2017 中使用标识列间隙【英文标题】:Using identity column gaps in SQL Server 2017 【发布时间】:2019-02-23 10:47:37 【问题描述】:

我的桌子上有几个 1000 次跳跃。我已经找到了原因,我想说的比较晚,这是频繁的服务器故障并重新启动并执行 set identity cache=off

希望这些大跳跃不会发生。现在我想在新条目的间隙中重用这些数字,最好的方法是什么?改变种子值是可能的吗?请注意,我无法更改任何现有数据。 另外,请注意添加新条目的速度很慢(每天少于 10 个条目),我可以密切关注这个数据库,并在必要时再次手动更改种子值。

非常感谢。

【问题讨论】:

为什么需要重复使用它们? IDENTITY 的目的是提供一个不断增加的值;不要使用每个值。如果交易失败,您是否也希望“倒退”? 为什么要这样做?为什么你不能接受跳跃? 这些 ID 用于将每个人与我的应用程序中的一些文件(照片)链接起来,因此它们会暴露给最终用户,小跳跃是可以接受的,但大的“1000”跳跃对我来说相当麻烦用户出于某种原因。 我认为这些数字对用户来说并不重要。但是您可以考虑进行一次批量操作以修复它们。不要试图插入它们之间 我认为没有充分的理由这样做。用户可以而且确实会做出不明智的决定和要求。用户 ID 只是一个数字,仅此而已。那是什么数字是完全任意且毫无意义的。它们是否连续无关紧要;你应该教育你的用户知道这一点。 【参考方案1】:

您可以在脚本的开头和结尾使用SET IDENTITY INSERT table_name ONSET IDENTITY INSERT table_name OFF 为每个实例编写脚本。完整的文档是here。您一次只能在一张桌子上使用它。

更改种子将无效,因为将始终使用下一个最高值。

以下脚本将有助于识别差距。

SELECT  TOP 1
    id + 1
FROM    mytable mo
WHERE   NOT EXISTS
    (
    SELECT  NULL
    FROM    mytable mi 
    WHERE   mi.id = mo.id + 1
    )
ORDER BY
    id

来自这个question/answer

更新

一种可能的策略是使数据库脱机,使用SET IDENTITY INSERT 用所需的 ID 填充间隙/跳转,但否则为最小/空数据,然后再次启用。然后使用空记录,直到全部使用,然后恢复到以前的方法。

【讨论】:

谢谢,但我怎么知道每次都有哪个值可用? 虽然这是可行的,但它会引入 OP 不知道的事务问题。它需要解决潜在的问题,以便 OP 可以为自己选择正确的方向 @Simonare 感谢您指出这一点。您将如何管理潜在的交易问题。 如果你设置了身份插入,你肯定不能。假设在第一个操作开始后又插入了一个。其他操作也将标识插入设置为关闭。但随后第一个操作完成,身份插入设置为 ON。第二个操作将使用身份插入,您的查询将失败,因为它将尝试插入 ID。对?使用这种方法并非万无一失 OP 可以做的一件事是长时间禁用身份插入。但是,如果有两个同时开始的操作,他可以​​获得相同的 ID 号。因为这个 OP 可以使用 TRANSACTIONS 来防止这个问题,但这意味着第二个事务需要等待第一个事务完成(阻塞会话)......【参考方案2】:

我认为这些数字对用户来说并不重要。但是您可以考虑进行一次批量操作以修复它们。不要试图插入它们之间

为表级别更改表的结构和设置身份插入,这不是事务安全的。

你需要编写 TSQL 脚本来同时改变你的基表和依赖表

【讨论】:

谢谢,它们对我的用户很重要,很遗憾,更改现有数据的 ID 不是一种选择。 但是为什么您的用户负责决定用户的唯一 ID 是什么@SchwanAbdulkareem?为什么这对他们很重要?如果您想要连续的数字,请考虑使用ROW_NUMBER 或其他方式给他们一个视图。不要让你的用户对一些如此随意的东西提出一个糟糕的(愚蠢的)要求,以至于重复使用“错过”的数字;您正在使用的产品设计遗漏的数字。就像我之前说的,这意味着当交易失败时你也需要“重用”数字。这不是你想去的兔子洞。 禁用身份缓存的决定也是另一个争论点。您需要专注于为什么会发生这些服务器故障? 事实上,“UserID”(数字)通常不会暴露给用户,这样做实际上可能是个坏主意(有很多系统被破坏的例子因为有人将 URL 从 userID=1271 更改为 userID=1272 并获得了其他人的详细信息)。暴露的是用户选择的用户名,这也应该是您的用户所看到的。 这是设计使然@SchwanAbdulkareem 并且有充分的理由(最大的原因之一是性能)。使用未缓存的身份值可能会大大降低服务器的性能;因为必须检查每个插入的标识值。如果您不喜欢该功能,则不应使用IDENTITY,而应考虑使用SEQUENCE

以上是关于在 SQL Server 2017 中使用标识列间隙的主要内容,如果未能解决你的问题,请参考以下文章

无法更新标识列 SQL Server 2014 [重复]

在 SQL Server Compact 中返回标识

使用sql语句创建修改SQL Server标识列(即自动增长列)

使用sql语句创建修改SQL Server标识列(即自动增长列)

SQL server非分隔标识符的规则

SQL Server中的标识列