Reset identity seed after deleting records in SQL

2019-01-01 16:33发布

I have inserted records into a SQL Server database table. The table had a primary key defined and the auto increment identity seed is set to “Yes”. This is done primarily because in SQL Azure, each table has to have a primary key and identity defined.

But since I have to delete some records from the table, the identity seed for those tables will be disturbed and the index column (which is auto-generated with an increment of 1) will get disturbed.

How can I reset the identity column after I deleted the records so that the column has sequence in ascending numerical order?

The identity column is not used as a foreign key anywhere in database.

17条回答
君临天下
2楼-- · 2019-01-01 16:56

The DBCC CHECKIDENT management command is used to reset identity counter. The command syntax is:

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

Example:

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

It was not supported in a previous versions of Azure SQL Database, but is supported now.


Please note that new_reseed_value argument is varied across SQL Server versions according to documentation:

If rows are present in the table, the next row is inserted with the new_reseed_value value. In version SQL Server 2008 R2 and earlier, the next row inserted uses new_reseed_value + the current increment value.

However, I find this information misleading (just plain wrong actually) because observed behaviour indicates that at least SQL Server 2012 is still uses new_reseed_value + the current increment value logic. Microsoft even contradicts with its own Example C found on same page:

C. Forcing the current identity value to a new value

The following example forces the current identity value in the AddressTypeID column in the AddressType table to a value of 10. Because the table has existing rows, the next row inserted will use 11 as the value, that is, the new current increment value defined for the column value plus 1.

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

Still, this all leaves an option for different behaviour on newer SQL Server versions. I guess the only way to be sure, until Microsoft clear up things in its own documentation, is to do actual tests before usage.

查看更多
闭嘴吧你
3楼-- · 2019-01-01 16:57
DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO

Where 0 is identity Start value

查看更多
素衣白纱
4楼-- · 2019-01-01 16:58

It should be noted that IF all of the data is being removed from the table via the DELETE (i.e. no WHERE clause), then as long as a) permissions allow for it, and b) there are no FKs referencing the table (which appears to be the case here), using TRUNCATE TABLE would be preferred as it does a more efficient DELETE and resets the IDENTITY seed at the same time. The following details are taken from the MSDN page for TRUNCATE TABLE:

Compared to the DELETE statement, TRUNCATE TABLE has the following advantages:

  • Less transaction log space is used.

    The DELETE statement removes rows one at a time and records an entry in the transaction log for each deleted row. TRUNCATE TABLE removes the data by deallocating the data pages used to store the table data and records only the page deallocations in the transaction log.

  • Fewer locks are typically used.

    When the DELETE statement is executed using a row lock, each row in the table is locked for deletion. TRUNCATE TABLE always locks the table (including a schema (SCH-M) lock) and page but not each row.

  • Without exception, zero pages are left in the table.

    After a DELETE statement is executed, the table can still contain empty pages. For example, empty pages in a heap cannot be deallocated without at least an exclusive (LCK_M_X) table lock. If the delete operation does not use a table lock, the table (heap) will contain many empty pages. For indexes, the delete operation can leave empty pages behind, although these pages will be deallocated quickly by a background cleanup process.

If the table contains an identity column, the counter for that column is reset to the seed value defined for the column. If no seed was defined, the default value 1 is used. To retain the identity counter, use DELETE instead.

So the following:

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

Becomes just:

TRUNCATE TABLE [MyTable];

Please see the TRUNCATE TABLE documentation (linked above) for additional information on restrictions, etc.

查看更多
忆尘夕之涩
5楼-- · 2019-01-01 16:58

Truncate table is preferred because it clears the records, resets the counter and reclaims the dis space.

Delete and CheckIdent should be used only where foreign keys prevent you from truncating

查看更多
弹指情弦暗扣
6楼-- · 2019-01-01 16:59

I tried @anil shahs answer and it reset the identity. But when a new row was inserted it got the identity = 2. So instead I changed the syntax to:

DELETE FROM [TestTable]

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

Then the first row will get the identity = 1.

查看更多
千与千寻千般痛.
7楼-- · 2019-01-01 16:59

Reset identity column with new id...

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

DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)
查看更多
登录 后发表回答