Index Fragmentation
The following script can be run in SSMS to identify and address index fragmentation.
This script identifies indexes with fragmentation levels above a specified threshold and either reorganizes
or rebuilds them based on the fragmentation percentage. The @DryRun variable allows you to test the script
without making changes.
Changing the @DryRun variable to 0 will execute the commands and should be performed during a maintenance
window because it may lock resources.
-- Configurable parameters
DECLARE @MinFrag FLOAT = 5.0;
DECLARE @MaxFrag FLOAT = 30.0;
DECLARE @DryRun BIT = 1; -- Set to 0 to execute
-- Logging table (optional)
IF OBJECT_ID('tempdb..#IndexMaintenanceLog') IS NOT NULL DROP TABLE #IndexMaintenanceLog;
CREATE TABLE #IndexMaintenanceLog (
LogTime DATETIME,
TableName NVARCHAR(128),
IndexName NVARCHAR(128),
Fragmentation FLOAT,
Action NVARCHAR(20),
Command NVARCHAR(MAX)
);
-- Cursor over fragmented indexes
DECLARE IndexCursor CURSOR FOR
SELECT
OBJECT_NAME(ps.object_id) AS TableName,
i.name AS IndexName,
ps.avg_fragmentation_in_percent,
i.object_id,
i.index_id
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ps
JOIN sys.indexes i ON ps.object_id = i.object_id AND ps.index_id = i.index_id
WHERE ps.database_id = DB_ID()
AND i.type_desc IN ('CLUSTERED', 'NONCLUSTERED')
AND i.is_disabled = 0
AND i.is_hypothetical = 0
AND ps.page_count > 100 -- Skip tiny indexes
AND ps.avg_fragmentation_in_percent >= @MinFrag;
DECLARE @TableName NVARCHAR(128), @IndexName NVARCHAR(128), @Frag FLOAT;
DECLARE @ObjId INT, @IdxId INT, @SQL NVARCHAR(MAX), @Action NVARCHAR(20);
OPEN IndexCursor;
FETCH NEXT FROM IndexCursor INTO @TableName, @IndexName, @Frag, @ObjId, @IdxId;
WHILE @@FETCH_STATUS = 0
BEGIN
IF @Frag BETWEEN @MinFrag AND @MaxFrag
BEGIN
SET @Action = 'REORGANIZE';
SET @SQL = 'ALTER INDEX [' + @IndexName + '] ON [' + @TableName + '] REORGANIZE;';
END
ELSE IF @Frag > @MaxFrag
BEGIN
SET @Action = 'REBUILD';
SET @SQL = 'ALTER INDEX [' + @IndexName + '] ON [' + @TableName + '] REBUILD;';
END
ELSE
BEGIN
SET @Action = 'SKIP';
SET @SQL = '-- Fragmentation below threshold';
END
INSERT INTO #IndexMaintenanceLog
VALUES (GETDATE(), @TableName, @IndexName, @Frag, @Action, @SQL);
IF @DryRun = 0 AND @Action IN ('REORGANIZE', 'REBUILD')
EXEC sp_executesql @SQL;
FETCH NEXT FROM IndexCursor INTO @TableName, @IndexName, @Frag, @ObjId, @IdxId;
END
CLOSE IndexCursor;
DEALLOCATE IndexCursor;
-- View log
SELECT * FROM #IndexMaintenanceLog ORDER BY LogTime;
Revised: 2025-08-15
Copied!