web-dev-qa-db-ja.com

断片化されたインデックスを再構築および再インデックス化するためのスクリプト?

'avg_fragmentation_in_percent'が特定の制限を超えた場合(カーソルが使用されない場合は良い)、誰でも断片化されたインデックスを再構築および再インデックスするためのスクリプトを提供できますか?

23
savitha

使用を再構築するには:

ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REBUILD

または使用を再編成するには:

ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REORGANIZE

再編成は、より低い(<30%)断片化で使用する必要がありますが、再構築(データベースにより重い)のみが断片化を0%に削減します。
詳細については、「 https://msdn.Microsoft.com/en-us/library/ms189858.aspx 」を参照してください。

26
KM.

2つのソリューション:1つはシンプルで、もう1つは高度です。

前書き

問題の深刻度に応じて、2つの解決策があります。

次のように、独自の値に置き換えます。

  • XXXMYINDEXXXXをインデックスの名前に置き換えます。
  • XXXMYTABLEXXXをテーブルの名前に置き換えます。
  • XXXDATABASENAMEXXXをデータベースの名前に置き換えます。

解決策1.インデックス作成

オフラインモードでテーブルのすべてのインデックスを再構築

ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD

オフラインモードでテーブルの1つの指定されたインデックスを再構築

ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD

ソリューション2.フラグメンテーション

断片化は、エントリが定期的に追加および削除されるテーブルの問題です。

フラグメンテーションの割合を確認

SELECT  
    ips.[index_id] ,
    idx.[name] ,
    ips.[avg_fragmentation_in_percent]
FROM    
    sys.dm_db_index_physical_stats(DB_ID(N'XXXMYDATABASEXXX'), OBJECT_ID(N'XXXMYTABLEXXX'), NULL, NULL, NULL) AS [ips]
    INNER JOIN sys.indexes AS [idx] ON [ips].[object_id] = [idx].[object_id] AND [ips].[index_id] = [idx].[index_id]

断片化5..30%

フラグメンテーション値が5%より大きく、30%より小さい場合、インデックスを再編成する価値があります。

テーブルのすべてのインデックスを再編成する

ALTER INDEX ALL ON XXXMYTABLEXXX REORGANIZE

テーブルに指定された1つのインデックスを再編成

ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REORGANIZE

フラグメンテーション30%+

フラグメンテーション値が30%以上の場合は、オンラインモードでインデックスを再構築する価値があります。

テーブルのオンラインモードですべてのインデックスを再構築

ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD WITH (ONLINE = ON)

テーブルのオンラインモードで1つの指定されたインデックスを再構築

ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD WITH (ONLINE = ON)
17

ここに、私が http://www.foliotek.com/devblog/sql-server-optimization-with-index-rebuilding から変更したスクリプトを示します。カーソルを使用しており、カーソルの主な問題は何かを知っていますが、カーソルのないバージョンに簡単に変換できます。

十分に文書化されており、簡単に読んでニーズに合わせて変更できます。

  IF OBJECT_ID('tempdb..#work_to_do') IS NOT NULL 
        DROP TABLE tempdb..#work_to_do

BEGIN TRY
--BEGIN TRAN

use yourdbname

-- Ensure a USE  statement has been executed first.

    SET NOCOUNT ON;

    DECLARE @objectid INT;
    DECLARE @indexid INT;
    DECLARE @partitioncount BIGINT;
    DECLARE @schemaname NVARCHAR(130);
    DECLARE @objectname NVARCHAR(130);
    DECLARE @indexname NVARCHAR(130);
    DECLARE @partitionnum BIGINT;
    DECLARE @partitions BIGINT;
    DECLARE @frag FLOAT;
    DECLARE @pagecount INT;
    DECLARE @command NVARCHAR(4000);

    DECLARE @page_count_minimum SMALLINT
    SET @page_count_minimum = 50

    DECLARE @fragmentation_minimum FLOAT
    SET @fragmentation_minimum = 30.0

-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.

    SELECT  object_id AS objectid ,
            index_id AS indexid ,
            partition_number AS partitionnum ,
            avg_fragmentation_in_percent AS frag ,
            page_count AS page_count
    INTO    #work_to_do
    FROM    sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL,
                                           'LIMITED')
    WHERE   avg_fragmentation_in_percent > @fragmentation_minimum
            AND index_id > 0
            AND page_count > @page_count_minimum;

IF CURSOR_STATUS('global', 'partitions') >= -1
BEGIN
 PRINT 'partitions CURSOR DELETED' ;
    CLOSE partitions
    DEALLOCATE partitions
END
-- Declare the cursor for the list of partitions to be processed.
    DECLARE partitions CURSOR LOCAL
    FOR
        SELECT  *
        FROM    #work_to_do;

-- Open the cursor.
    OPEN partitions;

-- Loop through the partitions.
    WHILE ( 1 = 1 )
        BEGIN;
            FETCH NEXT
FROM partitions
INTO @objectid, @indexid, @partitionnum, @frag, @pagecount;

            IF @@FETCH_STATUS < 0
                BREAK;

            SELECT  @objectname = QUOTENAME(o.name) ,
                    @schemaname = QUOTENAME(s.name)
            FROM    sys.objects AS o
                    JOIN sys.schemas AS s ON s.schema_id = o.schema_id
            WHERE   o.object_id = @objectid;

            SELECT  @indexname = QUOTENAME(name)
            FROM    sys.indexes
            WHERE   object_id = @objectid
                    AND index_id = @indexid;

            SELECT  @partitioncount = COUNT(*)
            FROM    sys.partitions
            WHERE   object_id = @objectid
                    AND index_id = @indexid;

            SET @command = N'ALTER INDEX ' + @indexname + N' ON '
                + @schemaname + N'.' + @objectname + N' REBUILD';

            IF @partitioncount > 1
                SET @command = @command + N' PARTITION='
                    + CAST(@partitionnum AS NVARCHAR(10));

            EXEC (@command);
            --print (@command); //uncomment for testing

            PRINT N'Rebuilding index ' + @indexname + ' on table '
                + @objectname;
            PRINT N'  Fragmentation: ' + CAST(@frag AS VARCHAR(15));
            PRINT N'  Page Count:    ' + CAST(@pagecount AS VARCHAR(15));
            PRINT N' ';
        END;

-- Close and deallocate the cursor.
    CLOSE partitions;
    DEALLOCATE partitions;

-- Drop the temporary table.
    DROP TABLE #work_to_do;
--COMMIT TRAN

END TRY
BEGIN CATCH
--ROLLBACK TRAN
    PRINT 'ERROR ENCOUNTERED:' + ERROR_MESSAGE()
END CATCH
10
Iman Abidi

次のスクリプトはインデックスの維持に非常に優れていることがわかりました。これを夜間または他の希望する時間枠で実行するようにスケジュールすることができます。

http://sqlfool.com/2011/06/index-defrag-script-v4-1/

4
Lima

2016年と2017年の本当の答えは次のとおりです。OlaHallengrenのスクリプトを使用します。

https://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html

私たちの相互進化のこの時点で、それは私たちの誰もが知る必要があるか、気にする必要があるすべてです。

3
Jonesome

REBUILD/REORGANIZEインデックスのクエリ

  • 30%<=再構築
  • 5%<=再編成
  • 5%>何もしない

クエリ:

SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName, 
ind.name AS IndexName, indexstats.index_type_desc AS IndexType, 
indexstats.avg_fragmentation_in_percent,
'ALTER INDEX ' + QUOTENAME(ind.name)  + ' ON ' +QUOTENAME(object_name(ind.object_id)) + 
CASE    WHEN indexstats.avg_fragmentation_in_percent>30 THEN ' REBUILD ' 
        WHEN indexstats.avg_fragmentation_in_percent>=5 THEN 'REORGANIZE'
        ELSE NULL END as [SQLQuery]  -- if <5 not required, so no query needed
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) indexstats 
INNER JOIN sys.indexes ind ON ind.object_id = indexstats.object_id 
    AND ind.index_id = indexstats.index_id 
WHERE 
--indexstats.avg_fragmentation_in_percent , e.g. >10, you can specify any number in percent 
ind.Name is not null 
ORDER BY indexstats.avg_fragmentation_in_percent DESC

出力

TableName      IndexName            IndexType              avg_fragmentation_in_percent SQLQuery
--------------------------------------------------------------------------------------- ------------------------------------------------------
Table1         PK_Table1            CLUSTERED INDEX        75                           ALTER INDEX [PK_Table1] ON [Table1] REBUILD 
Table1         IX_Table1_col1_col2  NONCLUSTERED INDEX     66,6666666666667             ALTER INDEX [IX_Table1_col1_col2] ON [Table1] REBUILD 
Table2         IX_Table2_           NONCLUSTERED INDEX     10                           ALTER INDEX [IX_Table2_] ON [Table2] REORGANIZE
Table2         IX_Table2_           NONCLUSTERED INDEX     3                            NULL
3
mr R