删除SQL Server中的logging后重置身份种子
我已经将logging插入到SQL Server数据库表中。 该表有一个主键定义和自动增量身份种子设置为“是”。 这主要是因为在SQL Azure中,每个表都必须定义一个主键和标识。
但是由于我不得不删除表中的一些logging,这些表的标识种子会受到干扰,索引列(自动生成的增量为1)会受到干扰。
在删除logging后,如何重置标识列,以便列的顺序按照升序排列?
数据库中的任何地方都不使用标识列作为外键。
DBCC CHECKIDENT
pipe理命令用于重置身份计数器。 命令语法是:
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议RESEED
为0
,虽然有些人认为这是TRUNCATED
表的缺陷,但Microsoft有一个解决scheme,将ID
DBCC CHECKIDENT ('[TestTable]', RESEED)
这将检查表并重置到下一个ID
。 从MS SQL 2005到现在,这已经可用了。
显式提供标识列的值
- 首先打开身份插入 –
SET Identity_Insert tblPerson ON
- 在插入查询中指定列表
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索引 ,不要担心失去一系列的身份,因为这是一个常见的情况。