- Latest
- Popular
Alexander Chigrik
This e-mail address is being protected from spambots. You need JavaScript enabled to view it
General Concepts
When you perform any data modification operations (INSERT, UPDATE, or DELETE statements)
table fragmentation can occur. When changes are made to the data that affect the
index, index fragmentation can occur and the information in the index can get scattered
in the database. Fragmented data can cause SQL Server to perform unnecessary data
reads, so a queries performance against a heavy fragmented table can be very poor.
If you want to determine the level of fragmentation, you can use the DBCC SHOWCONTIG
statement. The DBCC SHOWCONTIG statement displays fragmentation information for
the data and indexes of the specified table or view.
The DBCC SHOWCONTIG statement cannot automatically show fragmentation of all the
indexes on all the tables in a database it can only work on one table at a time.
You can write your own script to show fragmentation of all the tables in a database
or you can use the script below (this script shows fragmentation of all the tables
in the pubs database):
When you need to perform the same actions for all the tables in a database (when
you need to show the fragmentation of all the tables in a database, as in the script
above), you can create cursor for this purpose, or you can use the sp_MSforeachtable
undocumented system stored procedure to accomplish the same goal with less work.
The following script shows fragmentation of all the tables in the pubs database:
Keep in mind that the undocumented stored procedures could not be supported in the future SQL Server versions. So, you can use the sp_MSforeachtable undocumented system stored procedure at your own risk.
You can reduce fragmentation and improve read-ahead performance by using one of the following:
- Dropping and re-creating an index.
- Rebuilding an index by using the DBCC DBREINDEX statement.
- Defragmenting an index by using the DBCC INDEXDEFRAG statement.
Dropping and Re-creating an Index
This is a slowest way to reduce fragmentation, but dropping and re-creation of an
index can provide best performance. Because the leaf node of a nonclustered index
contains a clustered index key if the table has a clustered index, when a clustered
index is deleted on a table that has nonclustered indexes, the nonclustered indexes
are all rebuilt as part of the DROP operation. So, when you create a clustered index
on a table with several secondary indexes all of the secondary indexes must be rebuilt
so that the leaf nodes contain the clustering key value instead of the row identifier.
This can take significant time on a large table. So, if you need to drop and re-create
both clustered and nonclustered indexes drop the nonclustered indexes first and
the clustered index last, and then create clustered index first and the nonclustered
indexes last.
The main disadvantages of this method to reduce fragmentation is that during dropping
and recreating a clustered index:
- An exclusive table lock is put on the table, preventing any table access by your users.
- A shared table lock is put on the table, preventing all but SELECT operations to be performed on it.
When you create a clustered index, the table will be copied, the data in the table
will be sorted, and then the original table will be deleted. So, you should have
enough empty space to hold a copy of the data.
Rebuilding an Index
Rebuilding an index is a more efficient way to reduce fragmentation in comparison
with dropping and re-creating an index, this is because rebuilding an index is done
by one statement which is easier than coding multiple DROP INDEX and CREATE INDEX
statements. To rebuild indexes, you can use the DBCC DBREINDEX statement. The DBCC
DBREINDEX is automatically atomic (automatically atomic means that the work is done
by one statement and you don't need to do anything with this statement to be atomic).
Because the work is done by one statement, it can take advantage of more optimizations
with DBCC DBREINDEX than it can with individual DROP INDEX and CREATE INDEX statements.
You can rebuild all the indexes on all the tables in your database periodically
(for example, one time per week at Sunday) to reduce fragmentation. The DBCC DBREINDEX
statement cannot automatically rebuild all of the indexes on all the tables in a
database it can only work on one table at a time. You can write your own script
to rebuild all the indexes on all the tables in a database or you can use the script
below (the ind_rebuild stored procedure rebuilds all indexes with a fillfactor of
80 in every table in the current database):
You can use the sp_MSforeachtable undocumented system stored procedure to accomplish the same goal with less work.
This script rebuilds all indexes with a fillfactor of 80 in every table in the pubs database:
During rebuilding a clustered index, an exclusive table lock is put on the table, preventing any table access by your users, and during rebuilding a nonclustered index a shared table lock is put on the table, preventing all but SELECT operations to be performed on it, you should schedule DBCC DBREINDEX statement during CPU idle time and slow production periods.
Defragmenting an Index
SQL Server 2000 introduces a new DBCC INDEXDEFRAG statement to defragment clustered
and nonclustered indexes on tables and views. This statement defragments the leaf
level of the index so that the physical order of the index pages match the left-to-right
logical order of the leaf nodes. The DBCC INDEXDEFRAG statement will report to the
user an estimated percentage completed every five minutes and can be terminated
at any point in the process, so that any completed work is retained.
The main advantage of using DBCC INDEXDEFRAG in comparison with DBCC DBREINDEX or
with dropping and re-creating indexes is that the DBCC INDEXDEFRAG is an online
operation. This means that the DBCC INDEXDEFRAG statement does not hold locks for
a long time and thus will not block any running queries or updates. As the time
to defragment is related to the amount of fragmentation, you can use the DBCC INDEXDEFRAG
statement to reduce fragmentation if the index is not very fragmented. For a very
fragmented index, rebuilding (using DBCC DBREINDEX statement) can take less time.
You can defragment all the indexes on all the tables in your database periodically
(for example, one time per week at Sunday) to reduce fragmentation. The DBCC INDEXDEFRAG
statement cannot automatically defragment all of the indexes on all the tables in
a database; it can only work on one table and one index at a time. You can use the
script below to defragment all indexes in every table in the pubs database:
Though the DBCC INDEXDEFRAG, statement is an online operation, try to schedule it during CPU idle time and slow production periods as other maintenance tasks.





