Identity Overflow Check: How Close Is Each INT Column to 2,147,483,647

Identity overflow is about how many values you have used, not how many rows you have left. A table with a few thousand rows can be one insert away from an error. Here is a query that tells you how close every INT identity column is.

A sharpener beside a short usable pencil, an exhausted stub, and a fresh pencil

The error nobody planned for

Picture a 3 AM page. The orders application is failing on every insert. The message says “Arithmetic overflow error converting IDENTITY to data type int.” Someone checks the table and finds far fewer than two billion rows.

That is the trap. Old rows were purged, but the identity counter never went backward. The counter counts values handed out, and it only moves forward. So let me build a small lab at the edge and then write a check you can run on your own server.

Build three tables at the edge

I do not want to insert two billion rows, so I start the counters near the limits. IdentityUp starts at 2,147,483,645 and counts up by 2. IdentityDown starts at -2,147,483,646 and counts down by 1. IdentityUnused is a normal table that has never inserted a row. Run this in a test database. The last block drops all three.

DROP TABLE IF EXISTS dbo.IdentityUp;
DROP TABLE IF EXISTS dbo.IdentityDown;
DROP TABLE IF EXISTS dbo.IdentityUnused;

CREATE TABLE dbo.IdentityUp     (Id int IDENTITY(2147483645, 2),  Label char(1));
CREATE TABLE dbo.IdentityDown   (Id int IDENTITY(-2147483646, -1), Label char(1));
CREATE TABLE dbo.IdentityUnused (Id int IDENTITY,                  Label char(1));

INSERT dbo.IdentityUp (Label)   VALUES ('A');
INSERT dbo.IdentityDown (Label) VALUES ('B');

Calculate how many allocations are left

The check reads sys.identity_columns. It widens the values to bigint first, because subtracting from an INT limit inside an INT would overflow. Then it divides the room left by the step size and rounds down. A NULL last value means the table has never handed out a number.

WITH i AS (
    SELECT object_id, name,
           CONVERT(bigint, seed_value)      AS SeedValue,
           CONVERT(bigint, increment_value) AS IncrementValue,
           CONVERT(bigint, last_value)      AS LastValue
    FROM sys.identity_columns
    WHERE system_type_id = 56
      AND OBJECTPROPERTY(object_id, 'IsMSShipped') = 0)
SELECT OBJECT_SCHEMA_NAME(object_id) AS SchemaName,
       OBJECT_NAME(object_id)        AS TableName,
       name                          AS ColumnName,
       SeedValue, IncrementValue, LastValue,
       CASE WHEN IncrementValue > 0
            THEN (CONVERT(bigint, 2147483647) - LastValue) / IncrementValue
            ELSE (LastValue - CONVERT(bigint, -2147483648)) / (-IncrementValue)
       END AS FurtherAllocations
FROM i
ORDER BY SchemaName, TableName, ColumnName;

IdentityUp has one allocation left. IdentityDown has two. IdentityUnused shows NULL, because nothing has been allocated yet. This query covers the current database, so repeat it in each database you own. It checks INT columns only. For smallint or tinyint, change the type filter.

Cross the edge and read the error

Now use up the last value in IdentityUp. The next insert reaches 2,147,483,647, the INT maximum. One more insert fails, and the CATCH block shows the error.

INSERT dbo.IdentityUp (Label) VALUES ('C');

SELECT Id, Label FROM dbo.IdentityUp ORDER BY Id;

BEGIN TRY
    INSERT dbo.IdentityUp (Label) VALUES ('D');
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER() AS OverflowError, ERROR_MESSAGE() AS OverflowMessage;
END CATCH;
SQL Server results showing identity headroom and the caught overflow error
The descending identity has two further allocations, the ascending identity has one, and the unused identity is NULL. Exceeding the ascending limit raises error 8115.

The rows hold 2,147,483,645 and 2,147,483,647. The last attempt reports error 8115. SQL Server does not wrap around or skip ahead. It simply stops.

Rows are not allocations

Here is why a row count lies. The next block inserts A, then rolls back B, then inserts C. It then deletes everything and inserts D. In the end there is one row in the table, yet four values were used.

DROP TABLE IF EXISTS #Gap;
CREATE TABLE #Gap (Id int IDENTITY(1, 1), Label char(1));

INSERT #Gap (Label) VALUES ('A');
BEGIN TRAN;
INSERT #Gap (Label) VALUES ('B');
ROLLBACK;
INSERT #Gap (Label) VALUES ('C');
DELETE #Gap;
INSERT #Gap (Label) VALUES ('D');

SELECT COUNT(*) AS rows_in_table, MAX(Id) AS id_in_use FROM #Gap;

The result is one row and a highest Id of 4. The rollback burned a value, and the delete gave nothing back. This is why you forecast from LastValue and never from COUNT(*).

Rows are not allocations

Plan the fix before the alert turns red

Run the check on a schedule and keep dated results. A sudden jump tells you someone reseeded a table. Moving to BIGINT is the real cure, but it touches primary keys, foreign keys, indexes and application code. Give yourself months, not a weekend. Reseeding into the negative range buys time only if you have tested how old data and the application will cope.

DROP TABLE IF EXISTS #Gap;
DROP TABLE IF EXISTS dbo.IdentityUp;
DROP TABLE IF EXISTS dbo.IdentityDown;
DROP TABLE IF EXISTS dbo.IdentityUnused;

Run the check this week, while the numbers are still boring.

Identity headroom is not your row count, it is the range you have not yet used.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

SQL Identity, SQL Scripts, SQL Server
Previous Post
SQL SERVER – UNION ALL and ORDER BY – How to Order Table Separately While Using UNION ALL
Next Post
SQL SERVER – Function to Round Up Time to Nearest Minute Interval

Related Posts

1 Comment. Leave new

  • Congrats sir indeed a great success.

    Just would love to say the Quote that i always have in my mind.

    The woods are lovely, dark, and deep, But I have promises to keep, And miles to go before I sleep.

    Keep going …:)

    Just loved the last part of conversation between you and Shaivi.

    Best Regards,
    P.Anish Shenoy
    Bangalore.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.