Skip to content
  • There are no suggestions because the search field is empty.

T-SQL Script:  Automatic Index Maintenance Script

T-SQL Script: Automatic Index Maintenance Script (Reorganize or Rebuild depending on Index fragmentation )

SET NOCOUNT ON;

DECLARE 
    @object_id INT,
    @index_id INT,
    @schema_name SYSNAME,
    @table_name SYSNAME,
    @index_name SYSNAME,
    @frag FLOAT,
    @sql NVARCHAR(MAX);

-- Cursor over fragmented indexes
DECLARE cur CURSOR FOR
SELECT 
    ips.object_id,
    ips.index_id,
    ips.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i 
    ON ips.object_id = i.object_id 
    AND ips.index_id = i.index_id
WHERE 
    i.index_id > 0   -- ignore heaps
    AND ips.avg_fragmentation_in_percent > 5;  -- only process meaningful fragmentation

OPEN cur;
FETCH NEXT FROM cur INTO @object_id, @index_id, @frag;

WHILE @@FETCH_STATUS = 0
BEGIN
    SELECT 
        @schema_name = s.name,
        @table_name = t.name,
        @index_name = i.name
    FROM sys.objects t
    JOIN sys.schemas s ON t.schema_id = s.schema_id
    JOIN sys.indexes i ON t.object_id = i.object_id AND i.index_id = @index_id
    WHERE t.object_id = @object_id;

    IF @frag BETWEEN 5 AND 30
    BEGIN
        SET @sql = 
            'ALTER INDEX [' + @index_name + '] ON [' + @schema_name + '].[' + @table_name + '] REORGANIZE;';
        PRINT 'Reorganizing: ' + @schema_name + '.' + @table_name + ' (' + @index_name + ') — Fragmentation: ' + CAST(@frag AS VARCHAR(10));
    END
    ELSE IF @frag > 30
    BEGIN
        SET @sql = 
            'ALTER INDEX [' + @index_name + '] ON [' + @schema_name + '].[' + @table_name + '] REBUILD;';
        PRINT 'Rebuilding: ' + @schema_name + '.' + @table_name + ' (' + @index_name + ') — Fragmentation: ' + CAST(@frag AS VARCHAR(10));
    END

    EXEC(@sql);

    FETCH NEXT FROM cur INTO @object_id, @index_id, @frag;
END

CLOSE cur;
DEALLOCATE cur;

PRINT 'Index maintenance completed.';