Automate INDEX rebuild based on fragmentation results?

后端 未结 4 1887
心在旅途
心在旅途 2021-02-02 00:26

Is it possible to add a maintenance job to check indexes fragmentation. If greater than 50% then rebuild those indexes automatically ?

Index size can vary from 100MB to

4条回答
  •  鱼传尺愫
    2021-02-02 00:43

    I use this script . Please note I would advise you reading up about the dmv I am using here they are a hidden gem in SQL2005+.

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    CREATE TABLE #FragmentedIndexes
    (
     DatabaseName SYSNAME
     , SchemaName SYSNAME
     , TableName SYSNAME
     , IndexName SYSNAME
     , [Fragmentation%] FLOAT
    )
    
    INSERT INTO #FragmentedIndexes
    SELECT
     DB_NAME(DB_ID()) AS DatabaseName
     , ss.name AS SchemaName
     , OBJECT_NAME (s.object_id) AS TableName
     , i.name AS IndexName
     , s.avg_fragmentation_in_percent AS [Fragmentation%]
    FROM sys.dm_db_index_physical_stats(db_id(),NULL, NULL, NULL, 'SAMPLED') s
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
    AND s.index_id = i.index_id
    INNER JOIN sys.objects o ON s.object_id = o.object_id
    INNER JOIN sys.schemas ss ON ss.[schema_id] = o.[schema_id]
    WHERE s.database_id = DB_ID()
    AND i.index_id != 0
    AND s.record_count > 0
    AND o.is_ms_shipped = 0
    DECLARE @RebuildIndexesSQL NVARCHAR(MAX)
    SET @RebuildIndexesSQL = ''
    SELECT
     @RebuildIndexesSQL = @RebuildIndexesSQL +
    CASE
     WHEN [Fragmentation%] > 30
       THEN CHAR(10) + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON '
          + QUOTENAME(SchemaName) + '.'
          + QUOTENAME(TableName) + ' REBUILD;'
     WHEN [Fragmentation%] > 10
        THEN CHAR(10) + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON '
        + QUOTENAME(SchemaName) + '.'
        + QUOTENAME(TableName) + ' REORGANIZE;'
    END
    FROM #FragmentedIndexes
    WHERE [Fragmentation%] > 10
    DECLARE @StartOffset INT
    DECLARE @Length INT
    SET @StartOffset = 0
    SET @Length = 4000
    WHILE (@StartOffset < LEN(@RebuildIndexesSQL))
    BEGIN
     PRINT SUBSTRING(@RebuildIndexesSQL, @StartOffset, @Length)
     SET @StartOffset = @StartOffset + @Length
    END
    PRINT SUBSTRING(@RebuildIndexesSQL, @StartOffset, @Length)
    EXECUTE sp_executesql @RebuildIndexesSQL
    DROP TABLE #FragmentedIndexes
    

    Also keep in mind that this script can run a while and block access to your tables. Unless you have Enterprise editions SQL can LOCK the table when rebuilding the index. This will block all queries to that table using the index till the index defrag is finished. Thus it is not advised to run index rebuild during operational hours only during maintenance windows. If you are running enterprise edition you can use the ONLINE=ON option to defrag indexes online. This will use more space but your tables wont be blocked/locked during the defrag operation.

    Shout if you need more information.

    UPDATED:

    If you are running this query on a smaller database you can probably use the 'DETAILED' parameter in the call to sys.dm_db_index_physical_stats. This is probably a more detailed examination of the indexes. The discussion in the comments will also point out that on much larger tables it is probably worth doing a SAMPLED scan as this will help reduce the time needed to do the index scan.

提交回复
热议问题