如何在巨大的负载下在巨大的事务数据库中将主键的数据类型从 int 更改为 bigint?

Sae*_*ati 5 sql-server alter-table identity

这是一个遗留系统,每天处理 1000 万笔交易的表中有超过 10 亿条记录。

现在应用程序抱怨:

将 IDENTITY 转换为数据类型 int 时出现算术溢出错误

我们想将该id列的数据类型更改为bigint,但它无法执行并且超时。

我们应该做什么?我一点头绪也没有。我们无法停止系统,因为它是一个单一的应用程序和数据库,可以做很多事情。因此,我们不希望停止整个系统。

我们正在使用 SQL Server 10.50.6000.34,即 SQL Server 2008 R2 SP3(2014 年 9 月)

Mar*_*ith 7

假设您当前的表类似于

CREATE TABLE YourTable
  (
     Id           INT IDENTITY PRIMARY KEY,
     OtherColumns VARCHAR(10)
  )
Run Code Online (Sandbox Code Playgroud)

并且您现有的引用表的代码只是对表执行基本的 DQL 和 DML 命令(即SELECT/ UPDATEMERGEINSERTDELETE

并且在YourTable(Id)任何地方都没有被外键引用。

那么可能快速启动和运行的最佳方法(如果您无法承受一次性重建整个表的停机时间)将重命名该表(例如 as YourTableInt)并创建一个新表

CREATE TABLE YourTableBigInt
  (
     Id           BIGINT IDENTITY(2147483648, 1) PRIMARY KEY,
     OtherColumns VARCHAR(10)
  )
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建一个与原始表名同名的视图。

CREATE VIEW YourTable
AS
  SELECT Id,
         OtherColumns
  FROM   YourTableInt
  UNION ALL
  SELECT Id,
         OtherColumns
  FROM   YourTableBigInt 
Run Code Online (Sandbox Code Playgroud)

您需要编写INSTEAD OF将插入/更新/删除路由到适当表的触发器。这最初可能基于 Id 是否 <= 2147483647 ,但是如果您尝试将后台中的行从旧表迁移到新表,那么这将不起作用,因此最好执行以下操作。

删除触发器 通过加入 id 对两个表应用删除

更新触发器 通过加入 id 对两个表应用更新

插入触发器将 所有插入路由到新的“YourTableBigInt”表中。通过视图插入应该不可能输入可能与原始表中的任何内容发生冲突的显式标识,因为set identity_insert YourTable现在实际上是一个视图的任何尝试都将失败。

然后你可以有一个后台进程,删除从行的批次YourTableIntoutputŞ他们进入YourTableBigInt。一旦原始表为空,您可以删除它和视图并将 YourTableBigInt 重命名为 YourTable。


Sna*_*Jag 5

作为临时解决方案,因为你说你不能关闭系统,至少在短时间内......

请记住,数据类型是带符号的 INT(pos2bil 到 neg2bil),这意味着允许有 40 亿条记录,而不仅仅是 20 亿条。所以,为什么不考虑做一个 DBCC CHECKIDENT 来改变身份以从负 nbrs 递增,并让它去寻找另外 20 亿条记录,直到你弄清楚该怎么做。这应该是一个快速解决方案。

希望您不应该将 IDENT 用于 FK 以外的任何商业目的,例如 order by,如果 IDENT 是 CLUST,则需要关心磁盘上记录的顺序。

对使用的某些考虑因素非常小心,没有负面的 nbrs ......但是你处于一个艰难的境地,这可能对你有用,所以我只是提供一个出路的想法......

这是我不喜欢 IDENT 的签名数据类型的事情之一,“丢失”了 20 亿个条目。