Re-seeding a large sql table
Microsoft SQL Server 2008 R2 (SP3-OD) (KB3144114) - 10.50.6542.0 (Intel X86) Feb 22 2016 18:12:09 Copyright (c) Microsoft Corporation Standard Edition on Windows NT 5.2 <X86> (Build : )
I have a heavy table (135K rows), that I moved from another DB.
It transferred with the
[id] column being a standard
int column instead of it being the key & seed column.
When trying to edit that field to become an identity specification, with a seed value, its errors out and gives me this error:
Execution Timeout Expired. The timeout period elapsed prior to completion of the operation...
I even tried deleting that column, to try recreate it later, but i get the same issue.
CREATE TABLE [dbo].[tblEmailsSent]( [id] [int] IDENTITY(1,1) NOT NULL, -- this is what it should be. currently its just an `[int] NOT NULL` [Sent] [datetime] NULL, [SentByUser] [nvarchar](50) NULL, [ToEmail] [nvarchar](150) NULL, [StudentID] [int] NULL, [SubjectLine] [nvarchar](200) NULL, [MessageContent] [nvarchar](max) NULL, [ReadStatus] [bit] NULL, [Folder] [nvarchar](50) NULL, CONSTRAINT [PK_tblMessages] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO
One Solution collect form web for “Re-seeding a large sql table”
I think that your question is a duplicate of Adding an identity to an existing column. That question above has an answer that should be perfect for your situation. I’ll reproduce its essential part here below.
But before that, let’s clarify why you see the timeout error.
You are trying to add the
IDENTITY property to existing column. And you are using SSMS GUI for it. A simple
ALTER COLUMN statement can’t do it and even if it could, SSMS generates a script that creates a new table, copies over the data into the new table, drops the old table and renames the new table to the old name. When you do this operation via SSMS GUI it runs its scripts with a predefined timeout of 30 seconds.
Of course, you can change this setting in SSMS and increase the timeout, but there is a much better way.
- Simple/lazy way
Use SSMS GUI to change the column definition, but then instead of clicking “Save”, click “Generate Change Script” in the table designer.
Then save this script to a file and review the generated T-SQL code that GUI runs behind the scene.
You’ll see that it creates a temp table with the required schema, copies data over, re-creates foreign keys and indexes, drops the old table and renames the new table.
The script itself is usually correct, but pay close attention to transactions in it. For some reason SSMS often doesn’t use a single transaction for the whole operation, but several transactions. I’d recommend to manually review the script and make sure that there is only one
BEGIN TRANSACTION at the top and one
COMMIT in the end. You don’t want to end up with a half-done operation with, say, a table where all indexes and foreign keys were dropped.
If it is a one-off operation, it could be enough for you. Your table is only 2.4GB, so it may take few minutes, but it should not be hours.
If you run the T-SQL script yourself in SSMS, then by default there is no timeout. You can stop it yourself if it takes too long.
- Smart and fast way to do it is described in details in this answer by Justin Grant.
The main idea is to use the
ALTER TABLE...SWITCH statement to make the change only touching the metadata without touching each page of the table.
BEGIN TRANSACTION; -- create a new table with required schema CREATE TABLE [dbo].[NEW_tblEmailsSent]( [id] [int] IDENTITY(1,1) NOT NULL, [Sent] [datetime] NULL, [SentByUser] [nvarchar](50) NULL, [ToEmail] [nvarchar](150) NULL, [StudentID] [int] NULL, [SubjectLine] [nvarchar](200) NULL, [MessageContent] [nvarchar](max) NULL, [ReadStatus] [bit] NULL, [Folder] [nvarchar](50) NULL, CONSTRAINT [PK_tblEmailsSent] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -- switch the tables ALTER TABLE [dbo].[tblEmailsSent] SWITCH TO [dbo].[NEW_tblEmailsSent]; -- drop the original (now empty) table DROP TABLE [dbo].[tblEmailsSent]; -- rename new table to old table's name EXEC sp_rename 'NEW_tblEmailsSent','tblEmailsSent'; COMMIT;
After the new table has
IDENTITY property you normally should set the current identity value to the maximum of the actual values in your table. If you don’t do it, new rows inserted into the table would start from 1.
One way to do it is to run
DBCC CHECKIDENT after you switched the tables:
Alternatively, you can specify the new seed in the table definition:
CREATE TABLE [dbo].[NEW_tblEmailsSent]( [id] [int] IDENTITY(<max value of id + 1>, 1) NOT NULL,