Performance: Alter a table’s clustered index in SQL Server while keeping the table online

Back in the old SQL Server 2000 days, creating an index was a major
operation that would prevent queries and data modifications until it had
completed. Unless the index could be created in a few seconds, any new
indexes had to be performed during a maintenance period on the server.
Starting in SQL Server 2005, indexes can be created in an online mode,
allowing the table to queried and updated while the operation completes.
It’s a truly wonderful feature, which Microsoft knows and thus limits to
Enterprise edition. In other words, you have to pay extra for it.

During some recent performance tuning efforts, we determined that one of
the tables would benefit from having a different set of columns for its
clustered index. Since the clustered index represents the actual data
inside the table itself, I assumed that this was not a modification that
could be done while the table was online and would need to wait for a
maintenance period.

One of my colleagues informed me that this is not correct. It is in
fact possible to alter a clustered index in online mode. In this
situation, SQL Server is essentially creating a new copy of the
underlying table. It keeps the old table around to process queries, and
it makes data modifications on both. Once the new version of the table
is complete, it drops the old version.

--Get the name of the current clustered index
Select @IndexName = N'MyTable.'+[name] 
from sys.indexes 
where Object_id = OBJECT_ID('MyTable') 
And index_id = 1;

--If the name of the current clusted index does not match the name that we expect
--then rename it and rebuild it.
IF @IndexName <> N'MyTable.IDX_MyTable_MyIndexColumns'
            BEGIN
            Select 'rename and rebuild index'
            --rename the clustered index
            EXEC sp_rename @IndexName, N'IDX_MyTable_MyIndexColumns', N'INDEX';

            --recreate the clustered index--
            EXEC('CREATE CLUSTERED INDEX IDX_MyTable_MyIndexColumns on MyTable (MyColumn1, MyColumn2, MyColumn3) WITH (ONLINE = ON, DROP_EXISTING = ON ))
            END
ELSE IF @IndexName IS NULL --No Clustered index exists so just create it.
            BEGIN
            Select 'index not found so create it'
            EXEC('CREATE CLUSTERED INDEX IDX_MyTable_MyIndexColumns on MyTable (MyColumn1, MyColumn2, MyColumn3) WITH (ONLINE = ON))
            END
GO

You’ll notice that the script takes an extra step of renaming the
existing clustered index, if it exists. Since we name our indexes based
on the columns being indexed for readability, and we don’t want to
actually drop the clustered index itself, we rename to keep it
consistent.

This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s