How to See Rowcounts and Execution Time for In-Flight Queries in SQL Server
I frequently need to see rowcounts and execution time for queries while they’re running. Maybe I’m troubleshooting a slow query …
Read MoreBy Kendra Little on • 8 min read
You need to change an INT column to a BIGINT in a large table. Learn why this schema change can make your transaction log explode, and how to avoid it.
Prefer a podcast instead? Find it at kendralittle.com/dear-sql-dba-podcast.__
Show notes (transcript with links) are below the video.
Dear SQL DBA,
I have a 120GB table with 2 billion records and the Clustered Primary Key is an INT column. What’s the best way (and fastest) to convert this INT to a BIG INT?
The database is in the full recovery model, and I can take downtime up to a day on the weekend.
With Concern,
Billions and Billions Served
The integer data type in SQL Server allows numbers up to 2.147 billion rows (with a little change).
If you try to insert a row with a value above that, it fails with error 8115:
Msg 8115, Level 16, State 1, Line 142
Arithmetic overflow error converting IDENTITY to data type int.
At that point, you have to do something to insert more rows.
This seems straightforward at first. Let’s change the column to a bigint!
The first thing you notice is that you’re going to have to remove the Clustered Primary Key. You can’t change a data type with that there.
So we’re already in outage territory (even before you think about whether or not you have foreign keys defined against this PK or replication on the table).
Once you get to the point where you can alter the data, you run into a different problem:
This is because changing from INT to BIGINT is a “size-of-data” operation.
SQL Server has to go through and update Every. Single. Row.
And log it.
And SQL Server has to reserve extra space in the log in case it needs to roll back (because that will require additional logging).
If you get this far without thinking about how much log file you’re going to need and you run out, then things get extra slow, because most of that rollback’s going to be done by just one thread.
The integer data type can support down to -2.147 billion rows (and some change).
You can reset your identity column to -1 and work your way backwards by negative increments.
You can reset your identity all the way to the lowest possible value and work your way back towards zero.
Reseeding an identity column like duct tape: it’s a temporary solution, and you’re going to have to fix it for real later. And it’s unfamiliar duct tape.
Who looks at a brand of off brand duct tape and wants to use it to repair their roof?
If you do reseed to get things moving right away, the table just gets bigger, and the job of fixing it gets incrementally harder as time moves on.
This is pretty simple if you can take an outage. During the outage:
Do test this against a restored backup first so you can make sure you have all the details right and know how much data log and transaction log space you’re going to need. The work with all the indexes can still require substantial log usage.
SQL Server can do “minimal logging” in the Simple or Bulk Logged recovery model. NOT in the full recovery model. If your database is in the Full recovery model, you’re going to have to spend some time thinking about recovery models and backups.
With Bulk Logged recovery model:
With Simple Recovery model:
If your database is already in the Simple recovery model, then party, it’s easier. Just make sure you don’t try to get minimal logging while a backup is running, that doesn’t work.
The next step is to read the “Understanding Minimal Logged Operations” in the Data Loading Performance Guide.
If you’re inserting rows into a heap with no nonclustered indexes, typically you can get minimal logging by just using a TABLOCK hint.
If you’re inserting rows into an empty table with a clustered index, you may need additional hints or Trace Flag 610 on your statement.
There’s a handy dandy table in the whitepaper to make it easy.
Typically inserting into a heap with no indexes is the fastest option. If the speed of the change is important, test different inserts.
If you’re using SQL Server 2005, well, first it’s out of support. Second, it doesn’t allow minimal logging for INSERT SELECT operations, you have to do some SELECT FROM OPENROWSET (BULK ) weirdness.
Sometimes you just can’t take the outage. In that case, you’ve got to proceed with your own wits, and your own code. This is tricky because changes are occurring to the table.
The solution typically looks like this:
I’ve worked with cases of Extra Extra Large databases where schema changes were staged outside of production using SAN snapshots and new databases.
If you’ve got an XXL change, SAN magic can be a big help.
SQL Server 2012 added a feature where adding a new non-nullable column with default values is no longer a size of data operation.
This is an Enterprise Edition feature and it only works for non LOB types (no nvarchar(max), XML, etc). It’s also picky about rowsize.
Remus Rusanu wrote about this feature here in his article Online non-NULL with values column add in SQL Server 2012.
This doesn’t help our case here, because our existing Primary Key isn’t the same as a “default value”. But it might help some readers.
Aaron Bertrand has written a very detailed four part series with sample code. Start here to read the first article. (Links to the next three are at the bottom of the post.)
Kenneth Fisher wrote a great post about his experience with altering a column in a 750GB table in his article - Altering a column in a large table: a case study.
If you’d like to know more about how altering columns works internally, check out Remus Rusanu’s article, SQL Server table columns under the hood.
Copyright (c) 2025, Catalyze SQL, LLC; all rights reserved. Opinions expressed on this site are solely those of Kendra Little of Catalyze SQL, LLC. Content policy: Short excerpts of blog posts (3 sentences) may be republished, but longer excerpts and artwork cannot be shared without explicit permission.