如何减少标识值以避免整数溢出?

Ale*_*xei 5 sql-server identity sql-server-2014

我有一些叶表(对它们没有 FK),其中有几十万条记录,用于使用实体框架 ORM 同步一些外部数据。这涉及一些 DELETE,然后是 BULK INSERT。

对于大多数表,一些旧值可能会永远保留,所以我不能将 SEQUENCEs 与 CYCLE 一起使用,正如其中一条评论中所建议的那样。

一种影响是身份值会随着时间的推移不断增加,我希望能够降低它们的值。

这个问题及其答案解释了无法更新标识值,即使identity_insert表的标识值已打开。

一种快速的方法是将所有数据传输到缓冲表并通过重命名执行切换。类似于以下内容:

-- ActiveDirectoryCache_bak is the table I want to reduce identity values for
-- ActiveDirectoryCache_bak_buffer is a buffer table that will be renamed to ActiveDirectoryCache_bak once data transfer is ready

begin tran
select min(UserId), count(1) from ActiveDirectoryCache_bak
DBCC CHECKIDENT ('ActiveDirectoryCache_bak', NORESEED);  

-- Min UserId = 100, Count = 176041
-- Checking identity information: current identity value '204558', current column value '204558'.    

select * into ActiveDirectoryCache_bak_buffer
from ActiveDirectoryCache_bak
where 1 = 0

DBCC CHECKIDENT('ActiveDirectoryCache_bak_buffer', RESEED, 1)    

insert into ActiveDirectoryCache_bak_buffer
select LoginUsername, GivenName, MiddleName, Surname, EmailAddress
from ActiveDirectoryCache_bak

drop table ActiveDirectoryCache_bak

alter table ActiveDirectoryCache_bak_buffer add constraint PK_ActiveDirectoryCache_bak PRIMARY KEY (UserId)
EXEC sys.sp_rename 'ActiveDirectoryCache_bak_buffer', 'ActiveDirectoryCache_bak';

select min(UserId), count(1) from ActiveDirectoryCache_bak
DBCC CHECKIDENT ('ActiveDirectoryCache_bak', NORESEED);

-- Min UserId = 1, Count = 176041
-- Checking identity information: current identity value '176041', current column value '176041'.  

-- this should be replaced with commit when not in test mode
rollback
Run Code Online (Sandbox Code Playgroud)

我有能力在夜间进行此类操作,而且它们似乎只需要几秒钟的数据量(本示例为 4 秒)。

问题: 是否有任何方法可以避免执行完整数据复制以获得标识列的较小值?或者这是在我的上下文中最好的方法之一(合理的数据量并且能够锁定一些表几秒钟)。

Sol*_*zky 2

您可以尝试简单地删除并重新添加 Identity 列,而不复制整个表。这与您尝试使用问题中的代码具有相同的效果。这两种方法都不能真正按照问题中的“某些旧值可能永远保留”语句来处理保留现有行,但对于使用问题中的代码的任何情况,以下方法也应该有效。

您还应该考虑从最小值开始标识范围。从 1 开始,您将获得超过 21 亿个值,因此从最小值(或接近最小值)开始,您将获得 42 亿个值。因此,您将来不太可能需要进行此类重新种子操作。

设置

-- DROP TABLE dbo.IdentityTest;
CREATE TABLE dbo.IdentityTest
(
  ID INT IDENTITY(10203, 7) NOT NULL CONSTRAINT [PK_IdentityTest] PRIMARY KEY,
  SomethingElse UNIQUEIDENTIFIER NOT NULL,
  SomeName NVARCHAR(256) NOT NULL
);

INSERT INTO dbo.IdentityTest ([SomethingElse], [SomeName])
  SELECT NEWID(), so1.[name] + N'~' + so2.[name]
  FROM   master.sys.all_columns so1
  CROSS JOIN master.sys.objects so2;
-- 782,880 rows

SELECT * FROM dbo.IdentityTest;
Run Code Online (Sandbox Code Playgroud)

删除并重新创建身份 PK

BEGIN TRY
  BEGIN TRAN;

  ALTER TABLE dbo.IdentityTest
    DROP CONSTRAINT [PK_IdentityTest];

  ALTER TABLE dbo.IdentityTest
    DROP COLUMN [ID];

  ALTER TABLE dbo.IdentityTest
    ADD [ID] INT
    IDENTITY(-2140000000, 1)
    NOT NULL
    CONSTRAINT [PK_IdentityTest]
      PRIMARY KEY;

  COMMIT TRAN;
END TRY
BEGIN CATCH
  IF (@@TRANCOUNT > 0)
  BEGIN
    ROLLBACK TRAN;
  END;

  THROW;
END CATCH;

SELECT * FROM dbo.IdentityTest;
Run Code Online (Sandbox Code Playgroud)