SQL Identity (autonumber) is Incremented Even with a Transaction Rollback
Asked Answered
N

8

87

I have a .net transaction with a SQL insert to a SQL Server 2005 database. The table has an identity primary key.

When an error occurs within the transaction, Rollback() is called. The row inserts are rolled back correctly, however the next time I insert data to the table, the identity is incremented as if the rollback never occurred. So essentially there are gaps in the identity sequence. Is there any way to have the Rollback() method reclaim the missing identity?

Am I not approaching this the right way?

Nolanolan answered 11/11, 2008 at 23:5 Comment(3)
Sugested edit: change "autonumber" to "identity". Autonumber is MS Access terminology, while Identity is the proper term in SQL Server.Pouter
Yet to mark a post as answer? Are you still waiting for 'your answer'?Tatro
The highest voted answer makes zero attempt to actually answer the question of avoiding this behavior. Regardless of the approach being correct or not.Vallee
N
120

If you think about it, the auto-increment number should not be transactional. If other transactions had to wait to see if the auto-number was going to be used or "rolled back", they would be blocked by the existing transaction using the auto-number. For example, consider my psuedo code below with table A using an auto-number field for the ID column:

User 1
------------
begin transaction
insert into A ...
insert into B ...
update C ...
insert into D ...
commit


User 2
-----------
begin transaction
insert into A ...
insert into B ...
commit

If user 2's transaction starts a millisecond after user 1's, then their insert into table A would have to wait for user 1's entire transaction to complete just to see if the auto-number from the first insert into A was used.

This is a feature, not a bug. I would recommend using another scheme to generate auto-numbers if you need them to be tightly sequential.

Nucleolated answered 11/11, 2008 at 23:24 Comment(1)
Sequences feature starting SQL Server 2012 might help to create tightly sequential numbers - simple-talk.com/sql/learn-sql-server/sql-server-sequence-basicsWatermark
D
37

If you depend on your identity values being gapless, then yes - you are doing it wrong. The whole point of a surrogate key to is to have no business meaning.

And, no, there is no way to change this behaivor (short of rolling your own autoincrement, and suffering the performance consequences of blocking other inserts).

Deuteranope answered 12/11, 2008 at 1:11 Comment(0)
Q
16

You get gaps in your sequence if you DELETE a row too.

Sequences are required to be unique, but they are not required to be sequential. The fact that they are monotonically increasing is just a fluke of implementation.

Quarrelsome answered 11/11, 2008 at 23:56 Comment(0)
S
8

All the other posters who say not to worry about it, and that you should get gaps, are right. If there's business meaning to the number, and that meaning doesn't jive with gaps, then don't use an identity column.

FYI, if for whatever reason you DO want to remove the gaps, most databases have a way to reseed the auto-numbering to the number of your choice. It's a pain in the arse, and if you find yourself needing to do it regularly, you definitely shouldn't be using an autonumber / identity field, as noted above. But here's the code to do it in SQL server:

DBCC CHECKIDENT('Product', RESEED, 0)

That sets the product table to start back at 1 (though if you have records in the table, it'll obviously skip the ID values that are already taken.) Other RDBMS vendors have their own syntax, but the effect is roughly the same, so look up "reseed identity" or "reseed autonumber" in the system help files or internets.

Again: this is for special occasions, not regular use. Don't put it in a stored procedure and make us all come over there.

Sough answered 14/11, 2008 at 2:15 Comment(2)
In my mind reseed should only be used when removing test data to prepare for live data. ANd virtually never on a production system.Sabayon
"though if you have records in the table, it'll obviously skip the ID values that are already taken" - My experience is that this is not the case, and you will get a duplicate primary key constraint violation when you try to do an INSERT (tested on SQL Server 2008). You need to reseed it to the max identity value in the table. It will assign the next value, (i.e. pre-increment) on the next INSERT.Eschar
S
6

As far as I know the rows for insertion claim the autonumber and on rollback that number is lost for good. If you're depending on that autonumber being in sequencing you might want to consider the approach you're using.

Sporulate answered 11/11, 2008 at 23:10 Comment(0)
G
5

I don't think there is any requirement that autonumbered keys be sequential. In fact, I don't think they can be required to be:

  • transaction a starts and inserts

  • transaction b starts and inserts

  • transaction a aborts

    you get a hole. nothing to do about it.

Gifted answered 11/11, 2008 at 23:12 Comment(0)
P
1

Muhan try to think of it in the context of many simultaneous connections executing this transaction and not one at a time. Some will fail and some will succeed. You want SQL Server to concentrate on running the new requests as they come in and not on maintaining a gap-less identity column. IMO it (gaps in the values) is definitely something not worth spending time on.

Pentamerous answered 11/11, 2008 at 23:22 Comment(0)
J
1

No. Sequence implmentations use an autonomous transaction. In Oracle, the autonomous transaction was once internal to the dbms, but is now exposed for your own use (and is often used incorrectly)

PRAGMA AUTONOMOUS_TRANSACTION;' 
Jacquline answered 11/11, 2008 at 23:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.