Share via


Rebuild and Re-index Database Gradually

I had a problem in our live environment - the database was fragmented - badly.

A solution had to be written to defragment the database, whilst providing the least downtime - and the script below was born.

I create a function that will defrag the top X (in this case 20) indexes and created a SQL job that runs it every weekday - and another functions that defrags the top 60 indexes on Friday and Saturday nights. 

I am sure there is room for improvement - so let me know.

SQL SCRIPT:
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DB_Maint_Indexes]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[DB_Maint_Indexes]
GO
CREATE PROCEDURE [dbo].[DB_Maint_Indexes]
AS
BEGIN
-- This will work on MS SQL Server 2005+
-- Based on the websites:
-- http://msdn.microsoft.com/en-us/library/ms189858.aspx
-- http://msdn.microsoft.com/en-us/library/ms189858(v=SQL.105).aspx
-- http://msdn.microsoft.com/en-us/library/ms189858(v=SQL.90).aspx
--> 5% and < = 30% -  ALTER INDEX REORGANIZE 
--> 30% -  ALTER INDEX REBUILD WITH (ONLINE = ON)*

-- update all stats... use at your own discretion
--EXEC sp_updatestats;

DECLARE indexes_cur CURSOR
FOR
-- Change the top to the number of indexes you want to update
SELECT TOP 20
      CASE WHEN avg_fragmentation_in_percent > 30 THEN
      'ALTER INDEX ' + b.name + ' ON [' + s.name + '].[' + t.name 
      + '] REBUILD;'
      ELSE
      'ALTER INDEX ' + b.name + ' ON [' + s.name + '].[' + t.name 
      + '] REORGANIZE;' 
      END AS [sSQL]
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS a
    INNER JOIN sys.indexes AS b ON a.object_id = b.object_id AND a.index_id = b.index_id
    INNER JOIN sys.tables t on t.object_id = b.object_id 
      INNER JOIN sys.schemas s on t.schema_id = s.schema_id 
WHERE NOT b.name IS NULL
      AND avg_fragmentation_in_percent > 5
ORDER BY avg_fragmentation_in_percent DESC;

OPEN indexes_cur;
DECLARE @sSQL varchar(1024);
FETCH NEXT FROM indexes_cur INTO @sSQL;
WHILE (@@FETCH_STATUS = 0)
BEGIN
      -- EXECUTE THE SQL TO REBUILD THE INDEXES
      EXECUTE ('' + @sSQL + ';');
      FETCH NEXT FROM indexes_cur INTO @sSQL   
END;
CLOSE indexes_cur;
DEALLOCATE indexes_cur;
END

GO