web-dev-qa-db-fra.com

Script pour reconstruire et réindexer l'index fragmenté?

Quelqu'un peut-il fournir le script pour reconstruire et réindexer l'index fragmenté lorsque "avg_fragmentation_in_percent" dépasse certaines limites (mieux si le curseur n'est pas utilisé)?

23
savitha

Pour reconstruire l'utilisation:

ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REBUILD

ou pour réorganiser l'utilisation:

ALTER INDEX __NAME_OF_INDEX__ ON __NAME_OF_TABLE__ REORGANIZE

La réorganisation doit être utilisée à des fragmentations inférieures (<30%) mais seule la reconstruction (qui est plus lourde pour la base de données) réduit la fragmentation à 0%.
Pour plus d'informations, voir https://msdn.Microsoft.com/en-us/library/ms189858.aspx

26
KM.

Deux solutions: une simple et une plus avancée.

Introduction

Deux solutions s'offrent à vous selon la gravité de votre problème

Remplacez par vos propres valeurs, comme suit:

  • Remplacez XXXMYINDEXXXX par le nom d'un index.
  • Remplacez XXXMYTABLEXXX par le nom d'une table.
  • Remplacez XXXDATABASENAMEXXX par le nom d'une base de données.

Solution 1. Indexation

Reconstruire tous les index d'une table en mode hors ligne

ALTER INDEX ALL ON XXXMYTABLEXXX REBUILD

Reconstruire un index spécifié pour une table en mode hors ligne

ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REBUILD

Solution 2. Fragmentation

La fragmentation est un problème dans les tableaux auxquels des entrées sont régulièrement ajoutées et supprimées.

Vérifier le pourcentage de fragmentation

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]

Fragmentation 5..30%

Si la valeur de fragmentation est supérieure à 5%, mais inférieure à 30%, il convient de réorganiser les index.

Réorganiser tous les index d'une table

ALTER INDEX ALL ON XXXMYTABLEXXX REORGANIZE

Réorganiser un index spécifié pour une table

ALTER INDEX XXXMYINDEXXXX ON XXXMYTABLEXXX REORGANIZE

Fragmentation 30% +

Si la valeur de fragmentation est de 30% ou plus, il vaut la peine de reconstruire puis d'indexer en mode en ligne.

Reconstruire tous les index en mode en ligne pour une table

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

Reconstruire un index spécifié en mode en ligne pour une table

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

Voici le script modifié que j'ai extrait de http://www.foliotek.com/devblog/sql-server-optimization-with-index-rebuilding que j'ai trouvé utile de publier ici. Bien qu'il utilise un curseur et je sais quel est le principal problème avec les curseurs, il peut être facilement converti en une version sans curseur.

Il est bien documenté et vous pouvez facilement le lire et le modifier selon vos besoins.

  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

J'ai trouvé que le script suivant est très bon pour maintenir les index, vous pouvez le faire exécuter tous les soirs ou tout autre délai que vous souhaitez.

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

4
Lima

La vraie réponse, en 2016 et 2017, est: Utilisez les scripts d'Ola Hallengren:

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

C'est tout ce que chacun d'entre nous doit savoir ou s'inquiéter à ce stade de notre évolution mutuelle.

3
Jonesome

Requête pour les index RECONSTRUIRE/RÉORGANISER

  • 30% <= Reconstruire
  • 5% <= Réorganiser
  • 5%> ne rien faire

Requete:

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

Production

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