删除SQL Server中的logging后重置身份种子

我已经将logging插入到SQL Server数据库表中。 该表有一个主键定义和自动增量身份种子设置为“是”。 这主要是因为在SQL Azure中,每个表都必须定义一个主键和标识。

但是由于我不得不删除表中的一些logging,这些表的标识种子会受到干扰,索引列(自动生成的增量为1)会受到干扰。

在删除logging后,如何重置标识列,以便列的顺序按照升序排列?

数据库中的任何地方都不使用标识列作为外键。

DBCC CHECKIDENTpipe理命令用于重置身份计数器。 命令语法是:

 DBCC CHECKIDENT (table_name [, { NORESEED | { RESEED [, new_reseed_value ]}}]) [ WITH NO_INFOMSGS ] 

例:

 DBCC CHECKIDENT ('[TestTable]', RESEED, 0); GO 

以前版本的Azure SQL数据库不支持此function,但现在受支持。


请注意, 根据文档 , new_reseed_value参数在SQL Server版本中是不同的:

如果表中存在行,则使用new_reseed_value值插入下一行。 在版本SQL Server 2008 R2和更早版本中,插入的下一行使用new_reseed_value +当前增量值。

但是, 我发现这个信息误导 (实际上只是错误),因为观察到的行为表明至lessSQL Server 2012仍然使用new_reseed_value +当前增量值逻辑。 微软甚至与自己的Example C在同一页面上发现矛盾:

C.迫使当前的身份价值达到一个新的价值

以下示例强制AddressType表中的AddressTypeID列中的当前标识值的值为10.由于该表具有现有行,因此插入的下一行将使用11作为该值,也就是定义的新的当前增量值列值加1。

 USE AdventureWorks2012; GO DBCC CHECKIDENT ('Person.AddressType', RESEED, 10); GO 

尽pipe如此,所有这些都为更新的SQL Server版本留下了不同的行为选项。 我想唯一的方法是确保,直到微软清理自己的文档中的东西,是使用前做实际testing。

 DBCC CHECKIDENT ('TestTable', RESEED, 0) GO 

其中0是identity开始值

应该注意的是,如果所有的数据都通过DELETE从表中DELETE (即没有WHERE子句),那么只要a)权限允许,并且b)没有FK引用表(它出现在这里就是这种情况),使用TRUNCATE TABLE将是首选,因为它可以实现更高效的DELETE 并同时重置IDENTITY种子。 以下细节摘自TRUNCATE TABLE的MSDN页面:

与DELETE语句相比,TRUNCATE TABLE具有以下优点:

  • 使用更less的事务日志空间。

    DELETE语句一次删除一行,并在事务日志中logging每个删除行的条目。 TRUNCATE TABLE通过释放用于存储表数据的数据页来删除数据,并仅在事务日志中logging页解除分配。

  • 通常使用更less的锁。

    当使用行锁执行DELETE语句时,表中的每一行都被locking以供删除。 TRUNCATE TABLE总是locking表(包括一个模式(SCH-M)锁)和页面,但不是每一行。

  • 毫无例外,表格中还剩下零页。

    执行DELETE语句后,表格仍可以包含空白页面。 例如,如果没有至less一个独占的(LCK_M_X)表锁,堆中的空页将无法解除分配。 如果删除操作不使用表锁,则表(堆)将包含许多空白页。 对于索引,删除操作可以留下空白页面,虽然这些页面将通过后台清理过程快速解除分配。

如果表包含标识列,则该列的计数器将重置为为列定义的种子值。 如果没有定义种子,则使用默认值1。 要保留身份计数器,请使用DELETE。

所以如下:

 DELETE FROM [MyTable]; DBCC CHECKIDENT ('[MyTable]', RESEED, 0); 

只是成为:

 TRUNCATE TABLE [MyTable]; 

请参阅TRUNCATE TABLE文档(上面链接)了解有关限制等的其他信息。

我试过@anil shahs的答案,它重新设置了身份。 但是,当插入一个新行时,它的identity = 2 。 所以我改变了它的语法:

 DELETE FROM [TestTable] DBCC CHECKIDENT ('[TestTable]', RESEED, 0) GO 

那么第一行将得到身份= 1。

虽然大多数答案都build议RESEED为0,但是很多时候我们只需要再次填入下一个Id即可

 declare @max int select @max=max([Id])from [TestTable] if @max IS NUll //check when max is returned as null SET @max = 0 DBCC CHECKIDENT ('[TestTable]', RESEED,@max) 

这将检查表并重置到下一个ID。

虽然大多数答案都build议RESEED0 ,虽然有些人认为这是TRUNCATED表的缺陷,但Microsoft有一个解决scheme,将ID

 DBCC CHECKIDENT ('[TestTable]', RESEED) 

这将检查表并重置到下一个ID 。 从MS SQL 2005到现在,这已经可用了。

https://msdn.microsoft.com/en-us/library/ms176057.aspx

显式提供标识列的值

  1. 首先打开身份插入 – SET Identity_Insert tblPerson ON
  2. 在插入查询中指定列表Insert into tblPerson(PersonId, Name) values(2, 'John')

之后,填充标识列中的间隔,如果希望SQL Server计算该值,请closuresIdentity_Insert。

 SET Identity_Insert tblPerson OFF 

=============================

如果删除了表中的所有行,并且想要重置标识列值。

使用DBCC CHECKIDENT命令。

 DBCC CHECKIDENT(tblPerson, RESEED, 0) 

这个命令将重置PersonId标识列。

这是一个常见的问题,答案总是一样:不要这样做。 身份值应该被视为任意,因此,没有“正确”的顺序。

@jacob

 DBCC CHECKIDENT ('[TestTable]', RESEED,0) DBCC CHECKIDENT ('[TestTable]', RESEED) 

为我工作,我只需要从表中清除所有条目,然后在删除后添加上面的触发点。 现在每当我删除一个条目从那里被采取。

发布2命令可以做到这一点

 DBCC CHECKIDENT ('[TestTable]', RESEED,0) DBCC CHECKIDENT ('[TestTable]', RESEED) 

第一个重置身份为零,下一个将它设置为下一个可用的值 – 雅各

截断表是首选,因为它清除logging,重置计数器并回收dis空间。

删除和CheckIdent只能用于外键不能截断的地方

运行此脚本来重置标识列。 您需要进行两项更改。 用你需要更新的表replacetableXYZ。 此外,标识列的名称需要从临时表中删除。 这是一张35000行3列的表格。 显然,备份表并首先在testing环境中尝试这个。


 select * into #temp From tableXYZ set identity_insert tableXYZ ON truncate table tableXYZ alter table #temp drop column (nameOfIdentityColumn) set identity_insert tableXYZ OFF insert into tableXYZ select * from #temp 
 DBCC CHECKIDENT (<TableName>, reseed, 0) 

这会将当前身份值设置为0。

在插入下一个值时,标识值会增加到1。

重置身份栏与新ID …

DECLARE @MAX INT SELECT @ MAX = MAX(ISNULL(Id,0))FROM [TestTable]

DBCC CHECKIDENT('[TestTable]',RESEED,@ MAX)

第一:身份规范只是:“否”>>保存数据库执行项目

之后:标识规范只是:“是”>>保存数据库执行项目

您的数据库ID,PK从1 >>开始

使用这个存储过程:

 IF (object_id('[dbo].[pResetIdentityField]') IS NULL) BEGIN EXEC('CREATE PROCEDURE [dbo].[pResetIdentityField] AS SELECT 1 FROM DUMMY'); END GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[pResetIdentityField] @pSchemaName NVARCHAR(1000) , @pTableName NVARCHAR(1000) AS DECLARE @max INT; DECLARE @fullTableName NVARCHAR(2000) = @pSchemaName + '.' + @pTableName; DECLARE @identityColumn NVARCHAR(1000); SELECT @identityColumn = c.[name] FROM sys.tables t INNER JOIN sys.schemas s ON t.[schema_id] = s.[schema_id] INNER JOIN sys.columns c ON c.[object_id] = t.[object_id] WHERE c.is_identity = 1 AND t.name = @pTableName AND s.[name] = @pSchemaName IF @identityColumn IS NULL BEGIN RAISERROR( 'One of the following is true: 1. the table you specified doesn''t have an identity field, 2. you specified an invalid schema, 3. you specified an invalid table' , 16 , 1); RETURN; END; DECLARE @sqlString NVARCHAR(MAX) = N'SELECT @maxOut = max(' + @identityColumn + ') FROM ' + @fullTableName; EXECUTE sp_executesql @stmt = @sqlString, @params = N'@maxOut int OUTPUT', @maxOut = @max OUTPUT IF @max IS NULL SET @max = 0 print(@max) DBCC CHECKIDENT (@fullTableName, RESEED, @max) go --exec pResetIdentityField 'dbo', 'Table' 

它总是更好地使用TRUNCATE时,而不是删除所有logging,因为它也不使用日志空间。

如果我们需要删除并需要重置种子,请记住,如果没有填充表,并且使用了DBCC CHECKIDENT('tablenem',RESEED,0)则第一条logging将按照msdn文档中的说明得到identity = 0

在你的情况只重build索引 ,不要担心失去一系列的身份,因为这是一个常见的情况。