【问题标题】:Automatically set new seed value on Identity自动在 Identity 上设置新的种子值
【发布时间】:2012-04-14 03:17:18
【问题描述】:

类似问题:How to automatically reseed after using identity_insert?

我有一个每天运行一次的存储过程,该过程的一部分是从表中删除约百万行并重新插入相似数量的行(还有数百万其他行不受影响),一次它完成它重建表上的所有索引以供使用。

性能方面,我没有问题,唯一的烦恼是主键的大小过大 - 主键是IDENTITY INT - 显然,删除一百万行然后重新插入给我留下了〜每天1000000个缺口。

所以,我想在DELETE 之后的INSERT 之前重新设置 ID 列。

我知道我可以使用 CHECKIDENT 重新设定标识列的种子 - 但前提是在调用 CHECKIDENT 之前知道新的种子值 - 即在 CHECKIDENT 之前立即使用 MAX()

我的表是一个非常高流量的表,虽然不太可能,但在此过程中可能会尝试其他插入/删除的可能性很小,因此我有点担心诉诸 MAX()+1 来确定我的新的种子值(即在执行 MAX() 之后但在 CHECKIDENT 完成之前从其他地方插入的行 - 这将导致错误),例如:

DECLARE @NewSeed INT 
SELECT  @NewSeed = ISNULL(MAX(IdentityColumn), 0)
FROM    tbl_Whatever 
DBCC CHECKIDENT('tbl_Whatever', RESEED, @NewSeed) 

我的问题:有没有一种更巧妙的方法可以根据 Identity 列的当前最大值执行重新播种? - 我假设答案是否定的,但我只是想问一下。

SQL 版本是 2008 R2

【问题讨论】:

  • 只使用 BIGINT?如果超过 20 亿个正值还不够,BIGINT 会产生超过 90 亿个正值。
  • 如果我避免了差距,INT 就足够大了。切换到 BIGINT 将只是每行增加 4 个字节毫无意义(考虑到 5+ 百万行,这是很多浪费的字节(20MB?)) - 而且,它是实用性方面 - 例如,在接口/html表/报告上,我们不想要这些庞大的数字和令人困惑的差距
  • 这有点跑题了 - 抱歉 - 当你说不是所有的记录都被删除时,你是否保证未触及的记录没有高 id 值?如果您只留下一条记录,并且该记录具有最高的 id,那么您在这里没有任何好处。 [回到主题;我认为你只有这样做的唯一方法。]
  • 嗨,Dems,一个有效的问题。但是是的,我敢肯定,有问题的表格是基于日期的(未来 2 年以上的预订基于其他地方的元信息),根据日期删除行并重新插入更新版本。只有行 getdate() + 1 day 被删除,所有行
  • 为什么要加载这么多要删除的记录?为什么不让您的加载过程只选择您想要保留或加载到临时表的记录,然后在那里进行处理,然后发送到 prod 表?

标签: sql sql-server sql-server-2008 tsql sql-server-2008-r2


【解决方案1】:

使用事务来更新种子。这个操作速度很快,不用担心锁了。

【讨论】:

  • 只是为了添加答案。我很确定,如果您将获取 Max Id 的 Select 语句和 Insert 语句放在同一个事务中,SQL Server 将不允许在事务提交之前更新表。
  • 我就是这么说的:“这个操作太快了,你不用担心锁”。
  • 我并不是说您不必担心锁,因为它是如此之快,但是当事务打开时,表上会保留一个锁,这将阻止任何插入操作,直到事务已提交。
  • 同意,将 reseed 和 insert 包装到 1 个事务中似乎是最好的选择 - 标记为答案。
【解决方案2】:

正如 Dems 所说,将 Identity 设置为 Max + 1 并不能消除差距。
这更复杂,但它确实填补了空白。

  1. 删除
  2. 重置身份(在交易中)
  3. 判断是否有间隙
  4. 如果存在间隙,则插入 SET IDENTITY_INSERT ON 的行并填充间隙

显然存储过程需要确定下一个gap值。

如果您插入的数量与删除的数量一样多,您甚至不需要重置身份。

我认为你甚至可以让其他插入热,他们将使用自动标识

来自文档http://msdn.microsoft.com/en-us/library/ms188059.aspx

在任何时候,会话中只有一个表可以将 IDENTITY_INSERT 属性设置为 ON。如果一个表已经将此属性设置为 ON,并且为另一个表发出了 SET IDENTITY_INSERT ON 语句,则 SQL Server 会返回一条错误消息,指出 SET IDENTITY_INSERT 已为 ON,并报告为其设置了 ON 的表。

如果插入的值大于表的当前标识值,SQL Server 会自动使用新插入的值作为当前标识值。

【讨论】:

  • 如果你创建了一个存储过程,它需要在标识列中计算和插入值,以填补它的空白,你为什么不使用没有标识的常规列呢?这太过分了。
  • @JotaBe 矫枉过正??阅读问题陈述。这是一个带有其他插入和删除的活动表。我什至提到可以有其他插入热。大的间隙是由从这个存储过程中删除引起的。存储过程中的插入是可以缩小差距的受控环境。单独的插入仍然可以使用身份的便利。
  • 我的意思是,如果您要使用过程来填补空白,则不需要有一个身份列。在这种情况下,如果您使用常规列,您将摆脱设置身份插入开/关和重新播种的所有额外工作。
  • @JotaBe 这是对您立场的正确总结吗?保留现有结构并修改一个存储过程是大材小用。然而,改变表结构和修改所有表插入命令是不够的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-03
  • 2010-10-16
  • 2017-07-20
  • 2016-08-09
  • 2010-12-04
相关资源
最近更新 更多