Identity increment is jumping in SQL Server database
Asked Answered
I

6

153

In one of my tables Fee in column "ReceiptNo" in SQL Server 2012 database identity increment suddenly started jumping to 100s instead of 1 depending on the following two things.

  1. if it is 1205446 it is jumps to 1206306, if it is 1206321, it jumps to 1207306 and if it is 1207314, it jumps to 1208306. What I want to make you note is that the last three digits remain constant i.e 306 whenever the jumping occurs as shown in the following picture.

  2. this problem occurs when I restart my computer

enter image description here

Isotherm answered 3/1, 2013 at 19:52 Comment(9)
If you add order by ReceiptNo to your query are those records really not there? Are you sure when records are being inserted there are no errors? If a record attempts to get inserted and fails the identity will increment, same thing if records are deleted. If records are deleted the ReceiptNo does not reset. Can you post the create table for the Fee table?Tortosa
First question is - why does it matter? it should be an arbitrary unique IDSkindive
Is this running on a server or is it perhaps express on a desktop? Wondering why it seems the service is restarted so frequently?Antecede
@bluefeet I know when the error occurs, identity increment takes place. I'm 100% sure there are no errors. Im editing my question by adding table and the stored procedure that I use to insert the rows.Isotherm
@Isotherm - 99% sure that isn't needed. The jumps by exactly 1,000 (1206306, 1207306, 1207806) means the explanation in the Connect Item Thread almost certainly applies.Antecede
It is not a server. it is a local machine with windows 8 and sql server 2012 installed in it. pc is powered of whenever the coaching center is off. the next day when the center opens, they turn the pc on againIsotherm
@Isotherm - Well that explains it then. Every time it is powered off the unused numbers in that "batch" are lost then when it starts up again it will reserve another batch of 1,000 starting where that batch would have ended.Antecede
possible duplicate of Identity column value suddenly jumps to 1001 in sql serverMaximin
github.com/aspnet/EntityFrameworkCore/issues/8252Sain
A
188

You are encountering this behaviour due to a performance improvement since SQL Server 2012.

It now by default uses a cache size of 1,000 when allocating IDENTITY values for an int column and restarting the service can "lose" unused values (The cache size is 10,000 for bigint/numeric).

This is mentioned in the documentation

SQL Server might cache identity values for performance reasons and some of the assigned values can be lost during a database failure or server restart. This can result in gaps in the identity value upon insert. If gaps are not acceptable then the application should use its own mechanism to generate key values. Using a sequence generator with the NOCACHE option can limit the gaps to transactions that are never committed.

Additionally this gap can seemingly happen after some types of rolled back transaction. Fiddle.

From the data you have shown it looks like this happened after the data entry for 22 December then when it restarted SQL Server reserved the values 1206306 - 1207305. After data entry for 24 - 25 December was done another restart and SQL Server reserved the next range 1207306 - 1208305 visible in the entries for the 28th.

Unless you are restarting the service with unusual frequency any "lost" values are unlikely to make any significant dent in the range of values allowed by the datatype so the best policy is not to worry about it.

If this is for some reason a real issue for you some possible workarounds are...

  1. You can use a SEQUENCE instead of an identity column and define a smaller cache size for example and use NEXT VALUE FOR in a column default.
  2. Or apply trace flag 272 which makes the IDENTITY allocation logged as in versions up to 2008 R2. This applies globally to all databases.
  3. Or, for recent versions, execute ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF to disable the identity caching for a specific database.

You should be aware none of these workarounds assure no gaps. This has never been guaranteed by IDENTITY as it would only be possible by serializing inserts to the table (Without such serialisation identity value(s) can be allocated to an insert statement that ends up failing - e.g. due to constraint violation. Or to a transaction that is simply rolled back). If you need a truly gapless column you will need to use a different solution than either IDENTITY or SEQUENCE (example)

Antecede answered 3/1, 2013 at 19:57 Comment(9)
to verify what you said I inserted some values and got 1208309, 1208310 and then I restarted the server and then when I added the row I got 1209309 that means what you said is absolutely right. thanks alot. now can you plz tell me how can I solve this problem. would you suggest me to use sql server 2008 instead of 2012 that I was previously using or even using 2012 this problem can be resolved??Isotherm
@Isotherm - Is it actually a problem for you? Even if you use up 1,000 identity values a day it will still take 2 million days before you run out of values. If you do want the old behaviour you can set SQL Server to startup with trace flag 272 or you can use a SEQUENCE instead of an IDENTITY and set the Sequence to have a cache size of 0.Antecede
I got Quite Impressive and satisfactory answers from you for my solution thanks alot.Isotherm
Actually from your CREATE TABLE I see you are using numeric(7) and have started the numbering off at 1200001 that means you would run out after 8,799 days (24 years) if you use 1,000 per day.Antecede
The actual value "jumped" is supposed to be dependent on the column type used. For instance, a big int column will usually "jump" by 10,000 per restart.Proprietary
I've experienced this problem without any restart of the instance.Emphysema
I was running a debug instance of an application we have out in the wild. I had this happen and I almost had a heart attack thinking I'd somehow inadvertently been working on the live server! Thanks for this. Panic over :)Goatsbeard
check here the issue is reproduced to know what exactly is happening.Bunde
It's not really a problem, it just looks weird. I'm seeing it LocalDB. Small table, so I have 1, 2, 3, 4, 5, 1004, 1005.Indoctrinate
C
63

This problems occurs after restarting the SQL Server.

The solution is:

  • Run SQL Server Configuration Manager.

  • Select SQL Server Services.

    SQL Server Configuration Manager

  • Right-click SQL Server and select Properties.

  • In the opening window under Startup Parameters, type -T272 and click Add, then press Apply button and restart.

    SQL Server startup parameters

Coruscation answered 3/10, 2014 at 21:2 Comment(3)
This method is really work, thanks a lot! and as told here, this issue won't be fixed in SQL Server 2012, and in it's service packs, - only in next version release.Maximin
Is there a way to apply the trace flag to individual databases? I don't want to make this change on the whole server because I have third-party databases and I'm not sure how this will affect them.Wallie
I didn't follow the reasons, but apparently some users had to use lower case "t" to get it to work. See the link posted by Fragment in the comment above.Cantus
D
37

From SQL Server 2017+ you could use ALTER DATABASE SCOPED CONFIGURATION:

IDENTITY_CACHE = { ON | OFF }

Enables or disables identity cache at the database level. The default is ON. Identity caching is used to improve INSERT performance on tables with Identity columns. To avoid gaps in the values of the Identity column in cases where the server restarts unexpectedly or fails over to a secondary server, disable the IDENTITY_CACHE option. This option is similar to the existing SQL Server Trace Flag 272, except that it can be set at the database level rather than only at the server level.

(...)

G. Set IDENTITY_CACHE

This example disables the identity cache.

ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;
Demean answered 19/4, 2017 at 19:39 Comment(0)
H
28

I know my answer might be late to the party. But i have solved in another way by adding a start up stored procedure in SQL Server 2012.

Create a following stored procedure in master DB.

USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[ResetTableNameIdentityAfterRestart]
AS
BEGIN

begin TRAN
    declare @id int = 0
    SELECT @id =  MAX(id) FROM [DatabaseName].dbo.[TableName]
    --print @id
    DBCC CHECKIDENT ('[DatabaseName].dbo.[TableName]', reseed, @id)
Commit

END

Then add it in to Start up by using following syntax.

EXEC sp_procoption 'ResetOrderIdentityAfterRestart', 'startup', 'on';

This is a good idea if you have few tables. but if you have to do for many tables, this method still works but not a good idea.

Hyperaesthesia answered 30/3, 2015 at 23:31 Comment(3)
Good ideia. But it doesn't work for the dependent tables, does it? I mean, doest it fix the foreign key values?Ladybird
@rom5jp Fixing FK is not the point of this answer. Its all about fixing the possible next PK value of a table. As long as MAX(id) is not in any of the FK, it should work.Hyperaesthesia
Jumps in ID could matter when the taxman asks: "What happened to these 10000 invoices?" Though it's more supicious if just a few ID's are missing. So at least the workaround should be done for critical ID's.Maddox
E
17

This is still a very common issue among many developers and applications regardless of size.

Unfortunately the suggestions above do not fix all scenarios, i.e. Shared hosting, you cannot rely on your host to set the -t272 startup parameter.

Also, if you have existing tables that use these identity columns for primary keys, it is a HUGE effort to drop those columns and recreate new ones to use the BS sequence workaround. The Sequence workaround is only good if you are designing the tables new from scratch in SQL 2012+

Bottom line is, if you are on Sql Server 2008R2, then STAY ON IT. Seriously, stay on it. Until Microsoft admits that they introduced a HUGE bug, which is still there even in Sql Server 2016, then we should not upgrade until they own it and FIX IT.

Microsoft straight up introduced a breaking change, i.e. they broke a working API that no longer works as designed, due to the fact that their system forgets their current identity on a restart. Cache or no cache, this is unacceptable, and the Microsoft developer by the name of Bryan needs to own it, instead of tell the world that it is "by design" and a "feature". Sure, the caching is a feature, but losing track of what the next identity should be, IS NOT A FEATURE. It's a fricken BUG!!!

I will share the workaround that I used, because My DB's are on Shared Hosting servers, also, I am not dropping and recreating my Primary Key columns, that would be a huge PITA.

Instead, this is my shameful hack (but not as shameful as this POS bug that microsoft has introduced).

Hack/Fix:

Before your insert commands, just reseed your identity before each insert. This fix is only recommended if you don't have admin control over your Sql Server instance, otherwise I suggest reseeding on restart of server.

declare @newId int -- where int is the datatype of your PKey or Id column
select @newId = max(YourBuggedIdColumn) from YOUR_TABLE_NAME
DBCC CheckIdent('YOUR_TABLE_NAME', RESEED, @newId)

Just those 3 lines immediately before your insert, and you should be good to go. It really won't affect performance that much, i.e. it will be unnoticeable.

Goodluck.

Excursionist answered 7/3, 2017 at 14:6 Comment(0)
P
8

There are many possible reasons for jumping identity values. They range from rolled back inserts to identity management for replication. What is causing this in your case I can't tell without spending some time in your system.

You should know however, that in no case you can assume an identity column to be contiguos. There are just too many things that can cause gaps.

You can find a little more information about this here: http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/

Phylloquinone answered 3/1, 2013 at 19:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.