Similar Question: How to automatically reseed after using identity_insert?
I have a stored procedure that runs once a day, part of this procedure is to delete ~million rows from a table and re-insert a similar number of rows (there are millions of other rows that are not affected), once it finishes it rebuilds all the indexes on the table ready for use.
Performance wise, i have no problem, the only annoyance is the excessive size of the Primary Key - the primary key is an IDENTITY INT - obviously, deleting a million rows then re-inserting leaves me with a ~1000000 gap every day.
So, i want to reseed the ID column after the DELETE prior to the INSERT.
I know that i can use CHECKIDENT to reseed the identity column - but only if the new seed value is known before calling CHECKIDENT- i.e. using MAX() immediately prior to the CHECKIDENT.
My table is a very high traffic table, whilst it's unlikely, there is a small chance that other inserts / deletes may be attempted during this process, therefor i am a bit worried about resorting to MAX()+1 to determine my new seed value (i.e. a row being inserted from elsewhere after the MAX() was performed but prior to the completion of CHECKIDENT - wich would result in an error), eg:
DECLARE #NewSeed INT
SELECT #NewSeed = ISNULL(MAX(IdentityColumn), 0)
FROM tbl_Whatever
DBCC CHECKIDENT('tbl_Whatever', RESEED, #NewSeed)
My Question: is there a slicker way to perform a reseed based on the current max value of the Identity column? - I'm assuming the answer is no, but just thought i'd ask.
SQL Version is 2008 R2
Use a transaction to update the seed. This operation is so fast that you don't have to worry about locks.
As Dems said setting the Identity to Max + 1 does not eliminate gaps.
This is more complex but it does fill in gaps.
delete
reset identity (in a transaction)
determine if there are gaps
if there are gaps insert rows with SET IDENTITY_INSERT ON and fill in the gaps
Clearly the stored procedure needs to to determine the next gap value.
If you are inserting as many as you delete you don't even need to reset the identity.
I think you can even have other inserts hot and they will use the automatic identity
From the documentation http://msdn.microsoft.com/en-us/library/ms188059.aspx
At any time, only one table in a session can have the IDENTITY_INSERT property set to ON. If a table already has this property set to ON, and a SET IDENTITY_INSERT ON statement is issued for another table, SQL Server returns an error message that states SET IDENTITY_INSERT is already ON and reports the table it is set ON for.
If the value inserted is larger than the current identity value for the table, SQL Server automatically uses the new inserted value as the current identity value.
Related
Is it possible to reuse an identity field value after deleting rows in SQL Server 2008 Express? Here is an example. Suppose I have a table with an Id field as a primary key (identity). If I add five rows, I will have these 5 Ids: 1, 2, 3, 4, 5. If I were to delete these rows, and then add five more, the new rows would have Ids: 6, 7, 8, 9, 10. Is it possible to let it start over at 1 again?
Do I have to delete data from another table in order to accomplish this? Thanks for your help.
Is it possible to reuse an identity field value after deleting rows in SQL Server 2008 Express?
Yes, but it's one of the worst decisions you could make.
This is so bad that I'm not gonna explain how to do it, but just why this is bad.
We use identity columns to generate values that are unrelated to the data the table holds.
If we use identities as primary keys and we reuse their value, the same key will hold 2 (or more) different entities throughout time, giving place to confusion specially when generating reports or having other tables that use this key and don't have referential integrity.
Solutions used to identify unused values (infamous gaps and islands problem) are very slow when the amount of rows increase. This makes performance drop as rows piles up.
You will have to apply this "unused number" logic every time you insert rows on the table, so it's another thing to keep in mind on maintenance tasks.
There is little to none benefit of reusing these numbers as INT or BIGINT max values are high enough to support most business data.
It's common to use identities as primary keys or with a clustered index because new records will be inserted at the end, reducing fragmentation. Once records are deleted, it generates gaps in between pages (the swiss cheese pages), which is solved by doing index rebuilds. The problem comes after the rebuilds, where you will be potentially inserting new records massively in between and cause tons of page splits, hitting performance unnecessarily.
I can't possible think of a real case when you actually need to fill empty gaps in an identity column, as the purpose of this value is to be unrelated to the entity the table represents.
If you are going to remove all the data inside the table you can use TRUNCATE TABLE, which will help you remove whole data in table and reset the identity to start from the SEED value.
TRUNCATE TABLE MyTable
You can also use DBCC CHECKIDENT to reseed your identity to the spesific value.
DBCC CHECKIDENT ('dbo.MyTable', RESEED, 1);
The following code will reed the identity to start from 1.
Finally, if you need to cover the gaps, you need to know that, using IDENTITY you are mot able to cover the gaps, and you need to implement your custom function to behave like IDENTITY and cover the gaps.
We can do this by two ways.
If it is Non Pk Column, Insert the record with same Identity number then delete the previous identity column value.
If you don't need owl data drop the table and recreate that table or truncate the table and use DBCC CHECKIDENT to reseed your identity to the spesific value.
Possible if you remove Autoincrement attribute from ID.
You can keep a check if the table is empty or not and INSERT values accordingly.
A table was running with identity value in 100s few days back. When I inserted a new record suddenly it picked 1106 as value. Need to know who has reset the identity value on that table. Don't think there is a possibility of insertions and deletions on this table.
identity columns do not guarantee perfectly incremental values on every insert. It is most likely that no one has touched your table. If you are relying on this value being incremental, you should read up on the specs and redesign your database.
I have a table with a field that increments. The values for that field are 1, 2, 3...60 and then the field is 1060.
I don't know why?
The next value for id must be 61.
This is a new feature of SQL Server 2012. Identity columns use Sequences and values are cashed by default to speed up when inserting new rows. When unplanned shutdown of SQL Server occurs, cache is lost and Identity values continue with gap (of usually 1000 or 10000) created.
There could be several reasons - some of the most likely:
999 records were deleted
999 inserts were attempted and failed
Something reset the identity value using DBCC CHECKIDENT ({table}, RESEED, {value});
Something inserted a record with a specific ID using SET IDENTITY_INSERT ON
Autoincrement fields are not guaranteed to be consecutive. Thy are guaranteed to be unique. If you need them to be consecutive, then I would recommend keeping track of the next ID yourself, which will require you to think about concurrency, foreign key references, etc.
Am assuming you mean an IDENTITY field with an increment of 1.
This increases the value by 1 each time a new record is inserted.
To quote:
If an identity column exists for a table with frequent deletions, gaps
can occur between identity values. If this is a concern, do not use
the IDENTITY property. However, to ensure that no gaps have been
created or to fill an existing gap, evaluate the existing identity
values before explicitly entering one with SET IDENTITY_INSERT ON.
As alluded to in the comments it's likely this table once had data populated with all the missing values but these were deleted. (As this is quite a big chunk maybe this was done in bulk?)
Each time I restart my DB2 services, the auto increment field, always change by itself,
for example : before I restart, the auto increment value is at 13, and it's incremented by 1, and after I restart it's always become 31 and it's always incremented by 20
Any idea what may cause this?
Each time I restarted my Db2 service, I have to execute this command
ALTER TABLE <table> ALTER COLUMN <column> RESTART WITH 1
DB2 has a cache of generated values in order to reduce the overhead of generating values (Reduce the IO). This cache in memory, and assign the values as requested.
Take a look at the cache option when creating / altering the table. By default the cache value is 20.
It is important to understand how the sequeneces work in DB2. Sequences share many concepts with generated values / identity column.
Create table http://publib.boulder.ibm.com/infocenter/db2luw/v10r1/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
Alter table http://publib.boulder.ibm.com/infocenter/db2luw/v10r1/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000888.html
Sequences http://publib.boulder.ibm.com/infocenter/db2luw/v10r1/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/c0023175.html
From W3schools:
"Auto-increment allows a unique number to be generated when a new record is inserted into a table."
This is the only thing you may expect: unique (=non-conflicting) numbers. How these are generated is left to the DBMS. You must not expect a number sequence without any gaps.
For instance, a DBMS might choose to "pre-allocate" blocks of ten numbers (23..32, 33..42, ...) for performance reasons, so that the auto-increment field must only be incremented for every (up to) ten records. If you have an INSERT statement that inserts only 5 records into a newly created table, it can "acquire a block of 10 numbers" (0..9), use the first five values (0..4) of it and leave the rest unused. By acquiring this one block of numbers, the counter was incremented from 0 to 10. So the next INSERT statement that fetches a block will get the numbers ranging from 10 to 19.
I recently had to move a database(sql server 2008) to a different server, and I have noticed that in one of the table, the value of identity column has started to get some unexpected values. its set as identity column with identity increment 1 and identity seed 1. After every 10 consecutive entry or so, it would start from another much higher number and increment by 1 for next 10 entries or so and then jump up to another higher number. I can't seem to figure out the issue.
Sorry for the layman language. I am not a DB person.
This is likely not an issue with your identity key but an issue with a framework being used to insert data, or a SP. If you have a stored procedure that inserts data but then is ROLLBACK'd, the ID was reserved but the row is 'deleted'.
So two places to check: One on the frameworks you're using (NHibernate, or Entity Framework, etc?)... those frameworks might be inserting rows then deleting them. Second place to check is INSERT statements in SPROCs and other places you might expect a ROLLBACK.
See: SQL Identity (autonumber) is Incremented Even with a Transaction Rollback
Another issue is that you may just be examining data without sorting it? And when you ported the data you assumed it would be inserted or retrieved always in-ID-order. But because the new table is not 'indexed' the same way you won't necessarily see items in primary-key order. This is less likely if rows appear sequential most of the time with gaps, but worth mentioning.
The following will shed some light on your issue.
Create a table with an identity auto increment column
Insert 10 rows of random data
You will see that the ID values are 1,2,3,4,5,6,7,8,9,10
delete from mytable where id=10
insert another row into the table
now you will see the ID values are 1,2,3,4,5,6,7,8,9,**11**