Domanda

In SSW regole meglio di Database di SQL Server c'è un esempio di un completo piano di manutenzione database: SW.Nell'esempio vengono eseguiti sia a Riorganizzare Indice e quindi un Indice di Ricostruzione e quindi Aggiornare le Statistiche.C'è qualche punto di questo?Ho pensato di Riorganizzare Indice è stato un veloce ma meno efficace versione di Ricostruire l'Indice?e che la ricostruzione di un indice sarebbe anche aggiornare le statistiche automaticamente (indice cluster almeno).

È stato utile?

Soluzione

Facendo un REORGANIZE e poi un REBUILD sulla stessa indici è inutile, come tutte le modifiche da REORGANIZE sarebbe perso facendo il REBUILD.

Peggio è che nel piano di manutenzione schema da SSW, esegue una SHRINK in primo luogo, che i frammenti di indici come un effetto collaterale di modo che rilascia spazio.Quindi il REBUILD alloca lo spazio per il file di database di nuovo come spazio di lavoro durante il REBUILD operazione.

  • REORGANIZE è un'operazione in linea che consente di deframmentare pagine foglia in un cluster o un indice non cluster pagina per pagina utilizzando piccolo extra spazio di lavoro.

  • REBUILD è un'operazione in linea con le edizioni Enterprise, collegato in altre edizioni, e utilizza una quantità supplementare di spazio di lavoro di nuovo come la dimensione dell'indice.Crea una nuova copia dell'indice e quindi elimina la vecchia, così sbarazzarsi di frammentazione.Vengono ricalcolate le statistiche di default come parte di questa operazione, ma che può essere disattivato.

Vedere Riorganizzazione e Ricostruzione degli Indici per ulteriori informazioni.

Non utilizzare SHRINK tranne che con il TRUNCATEONLY opzione e poi anche se il file crescerà di nuovo, allora si dovrebbe riflettere se è necessario:

sqlservercentral_SHRINKFILE

Altri suggerimenti

La riorganizzazione e ricostruzione sono cose diverse.

Riorganizzare:si tratta di un defrag per gli indici.Prende l'indice esistente(es) e deframmenta pagine esistenti.Tuttavia, se le pagine non sono in un modo contiguo, si rimane come prima.Solo il contenuto delle pagine stanno cambiando.

Ricostruzione:in realtà non si scende l'indice e lo ricrea da zero.Significa che si otterrà un completamente nuovo indice, con deframmentato e pagine contigue.

Inoltre con la ricostruzione è possibile modificare il partizionamento o gruppi di file, ma con la riorganizzazione si può defrag non solo l'intero indice, ma anche solo una partizione dell'indice.

L'aggiornamento delle statistiche è automatica indici cluster, ma non non cluster quelli.

Prima di considerare la manutenzione di indici, è importante rispondere a due domande fondamentali:

  1. Qual è il grado di frammentazione?
  2. Che cosa è l'azione appropriata?Riorganizzare o ricostruire?

Come descritto in questo articolo http://solutioncenter.apexsql.com/why-when-and-how-to-rebuild-and-reorganize-sql-server-indexes/, e per aiutare a determinare se si dovrebbe eseguire la ricostruzione di un indice o di un indice riorganizzazione, la preghiamo di comprendere i seguenti:

  • Indice di riorganizzazione è un processo in cui SQL Server passa indice esistente e pulisce.Ricostruzione di un indice è un pesante processo dove l'indice viene eliminato e ricreato da zero, completamente nuova struttura, libero da tutti ammucchiati frammenti e vuoto-spazio pagine.

  • Mentre l'indice di riorganizzazione è una pura operazione di pulizia che lascia dello stato del sistema, in quanto priva di blocco interessato tabelle e viste, il processo di ricostruzione serrature tabella interessata, per l'intero periodo di rigenerazione, il che può comportare lunghi tempi di inattività che non può essere accettabile in alcuni ambienti.Con questo in mente, è chiaro che la ricostruzione dell'indice, è un processo con più "forti" soluzione, ma si tratta di un prezzo – possibile serrature a lungo interessati tabelle indicizzate.

Dall'altro lato, indice di riorganizzazione è un ‘leggero’ processo per risolvere la frammentazione in un meno efficace – dal puliti indice sarà sempre seconda al nuovo completamente fatto da zero.Ma la riorganizzazione indice è molto meglio dal punto di vista di efficienza, dal momento che non si blocca interessato tabella indicizzata durante il corso dell'operazione.

L'articolo di cui sopra spiega anche come riorganizzare e ricostruire gli indici utilizzando sql server management studio, T-SQL (per riorganizzare/ricostruire gli indici di una tabella) e un 3rd party strumento chiamato ApexSQL di Backup.

Quando si fa una riorganizzazione di un indice, l'indice è disposta su due o più file fisici i dati potranno essere deframmentato interno del file di dati.Le pagine non vengono spostati da un file di dati di un altro.

Quando l'indice è in un unico file la riorganizzazione e il reindex avrà lo stesso risultato finale.

Alcune volte la riorganizzazione sarà più veloce, e alcune volte il reindex sarà più veloce a seconda del grado di frammentazione dell'indice.Meno frammentato l'indice quindi di una riorganizzazione sarà più veloce, più frammentato, più lenta è la riorganizzazione sarà, ma il più veloce di un reindex sarà.

Esattamente quello che Biri detto.Ecco come vorrei il reindex di un intero database:

EXEC [sp_MSforeachtable] @command1="RAISERROR('DBCC DBREINDEX(''?'') ...',10,1) WITH NOWAIT DBCC DBREINDEX('?')"

Io Uso questo SP

CREATE PROCEDURE dbo.[IndexRebuild]
AS 
DECLARE @TableName NVARCHAR(500);
DECLARE @SQLIndex NVARCHAR(MAX);
DECLARE @RowCount INT;
DECLARE @Counter INT;

DECLARE @IndexAnalysis TABLE
    (
      AnalysisID INT IDENTITY(1, 1)
                     NOT NULL
                     PRIMARY KEY ,
      TableName NVARCHAR(500) ,
      SQLText NVARCHAR(MAX) ,
      IndexDepth INT ,
      AvgFragmentationInPercent FLOAT ,
      FragmentCount BIGINT ,
      AvgFragmentSizeInPages FLOAT ,
      PageCount BIGINT
    )

BEGIN
    INSERT  INTO @IndexAnalysis
            SELECT  [objects].name ,
                    'ALTER INDEX [' + [indexes].name + '] ON ['
                    + [schemas].name + '].[' + [objects].name + '] '
                    + ( CASE WHEN (   [dm_db_index_physical_stats].avg_fragmentation_in_percent >= 20
                                    AND [dm_db_index_physical_stats].avg_fragmentation_in_percent < 40
                                  ) THEN 'REORGANIZE'
                             WHEN [dm_db_index_physical_stats].avg_fragmentation_in_percent > = 40
                             THEN 'REBUILD'
                        END ) AS zSQL ,
                    [dm_db_index_physical_stats].index_depth ,
                    [dm_db_index_physical_stats].avg_fragmentation_in_percent ,
                    [dm_db_index_physical_stats].fragment_count ,
                    [dm_db_index_physical_stats].avg_fragment_size_in_pages ,
                    [dm_db_index_physical_stats].page_count
            FROM    [sys].[dm_db_index_physical_stats](DB_ID(), NULL, NULL,
                                                       NULL, 'LIMITED') AS   [dm_db_index_physical_stats]
                    INNER JOIN [sys].[objects] AS [objects] ON (   [dm_db_index_physical_stats].[object_id] = [objects].[object_id] )
                    INNER JOIN [sys].[schemas] AS [schemas] ON ( [objects].[schema_id]  = [schemas].[schema_id] )
                    INNER JOIN [sys].[indexes] AS [indexes] ON (  [dm_db_index_physical_stats].[object_id] = [indexes].[object_id]
                                                          AND  [dm_db_index_physical_stats].index_id = [indexes].index_id
                                                          )
            WHERE   index_type_desc <> 'HEAP'
                    AND [dm_db_index_physical_stats].avg_fragmentation_in_percent > 20
END

SELECT  @RowCount = COUNT(AnalysisID)
FROM    @IndexAnalysis

SET @Counter = 1
WHILE @Counter <= @RowCount 
    BEGIN

        SELECT  @SQLIndex = SQLText
        FROM    @IndexAnalysis
        WHERE   AnalysisID = @Counter

        EXECUTE sp_executesql @SQLIndex

        SET @Counter = @Counter + 1

    END
 GO

e creare Un Lavoro che comportano l'esecuzione di questo SP ogni settimana.

Ancora meglio è:

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REINDEX'

o

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REORGANIZE'

I miei due centesimi...Questo metodo segue le specifiche riportate sull'tech net: http://technet.microsoft.com/en-us/library/ms189858(v=sql.105).aspx

USE [MyDbName]
GO

SET ANSI_NULLS OFF
GO

SET QUOTED_IDENTIFIER OFF
GO

CREATE PROCEDURE [maintenance].[IndexFragmentationCleanup]
AS
DECLARE @reIndexRequest VARCHAR(1000)

DECLARE reIndexList CURSOR
FOR
SELECT INDEX_PROCESS
FROM (
    SELECT CASE 
            WHEN avg_fragmentation_in_percent BETWEEN 5
                    AND 30
                THEN 'ALTER INDEX [' + i.NAME + '] ON [' + t.NAME + '] REORGANIZE;'
            WHEN avg_fragmentation_in_percent > 30
                THEN 'ALTER INDEX [' + i.NAME + '] ON [' + t.NAME + '] REBUILD with(ONLINE=ON);'
            END AS INDEX_PROCESS
        ,avg_fragmentation_in_percent
        ,t.NAME
    FROM sys.dm_db_index_physical_stats(NULL, NULL, NULL, NULL, NULL) AS a
    INNER JOIN sys.indexes AS i ON a.object_id = i.object_id
        AND a.index_id = i.index_id
    INNER JOIN sys.tables t ON t.object_id = i.object_id
    WHERE i.NAME IS NOT NULL
    ) PROCESS
WHERE PROCESS.INDEX_PROCESS IS NOT NULL
ORDER BY avg_fragmentation_in_percent DESC

OPEN reIndexList

FETCH NEXT
FROM reIndexList
INTO @reIndexRequest

WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY

        PRINT @reIndexRequest;

        EXEC (@reIndexRequest);

    END TRY

    BEGIN CATCH
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = 'UNABLE TO CLEAN UP INDEX WITH: ' + @reIndexRequest + ': MESSAGE GIVEN: ' + ERROR_MESSAGE()
            ,@ErrorSeverity = 9 
            ,@ErrorState = ERROR_STATE();

    END CATCH;

    FETCH NEXT
    FROM reIndexList
    INTO @reIndexRequest
END

CLOSE reIndexList;

DEALLOCATE reIndexList;

RETURN 0

GO

Ho cercato sul web e ho trovato alcuni ottimi articoli.Alla fine ho scritto la funzione di script e al di sotto della quale è riorganizzare, ricreare e ricostruire tutti gli indici in un database.

Il primo potrebbe essere necessario leggere questo articolo per capire perché non siamo solo di ricreare tutti gli indici.

Secondo, abbiamo bisogno di una funzione per creare script di creazione dell'indice.Così questo articolo può essere di aiuto.Anche io sto condivisione di lavoro la funzione qui sotto.

Ultima fase di un ciclo while per trovare e organizzare tutti gli indici del database. Questo video è grata esempio per fare questo.

Funzione:

create function GetIndexCreateScript(
    @index_name nvarchar(100)
) 
returns nvarchar(max)
as
begin

declare @Return   varchar(max)

SELECT @Return = ' CREATE ' + 
    CASE WHEN I.is_unique = 1 THEN ' UNIQUE ' ELSE '' END  +  
    I.type_desc COLLATE DATABASE_DEFAULT +' INDEX ' +   
    I.name  + ' ON '  +  
    Schema_name(T.Schema_id)+'.'+T.name + ' ( ' + 
    KeyColumns + ' )  ' + 
    ISNULL(' INCLUDE ('+IncludedColumns+' ) ','') + 
    ISNULL(' WHERE  '+I.Filter_definition,'') + ' WITH ( ' + 
    CASE WHEN I.is_padded = 1 THEN ' PAD_INDEX = ON ' ELSE ' PAD_INDEX = OFF ' END + ','  + 
    'FILLFACTOR = '+CONVERT(CHAR(5),CASE WHEN I.Fill_factor = 0 THEN 100 ELSE I.Fill_factor END) + ','  + 
    -- default value 
    'SORT_IN_TEMPDB = OFF '  + ','  + 
    CASE WHEN I.ignore_dup_key = 1 THEN ' IGNORE_DUP_KEY = ON ' ELSE ' IGNORE_DUP_KEY = OFF ' END + ','  + 
    CASE WHEN ST.no_recompute = 0 THEN ' STATISTICS_NORECOMPUTE = OFF ' ELSE ' STATISTICS_NORECOMPUTE = ON ' END + ','  + 
    -- default value  
    ' DROP_EXISTING = ON '  + ','  + 
    -- default value  
    ' ONLINE = OFF '  + ','  + 
   CASE WHEN I.allow_row_locks = 1 THEN ' ALLOW_ROW_LOCKS = ON ' ELSE ' ALLOW_ROW_LOCKS = OFF ' END + ','  + 
   CASE WHEN I.allow_page_locks = 1 THEN ' ALLOW_PAGE_LOCKS = ON ' ELSE ' ALLOW_PAGE_LOCKS = OFF ' END  + ' ) ON [' + 
   DS.name + ' ] '  
FROM sys.indexes I   
 JOIN sys.tables T ON T.Object_id = I.Object_id    
 JOIN sys.sysindexes SI ON I.Object_id = SI.id AND I.index_id = SI.indid   
 JOIN (SELECT * FROM (  
    SELECT IC2.object_id , IC2.index_id ,  
        STUFF((SELECT ' , ' + C.name + CASE WHEN MAX(CONVERT(INT,IC1.is_descending_key)) = 1 THEN ' DESC ' ELSE ' ASC ' END 
    FROM sys.index_columns IC1  
    JOIN Sys.columns C   
       ON C.object_id = IC1.object_id   
       AND C.column_id = IC1.column_id   
       AND IC1.is_included_column = 0  
    WHERE IC1.object_id = IC2.object_id   
       AND IC1.index_id = IC2.index_id   
    GROUP BY IC1.object_id,C.name,index_id  
    ORDER BY MAX(IC1.key_ordinal)  
       FOR XML PATH('')), 1, 2, '') KeyColumns   
    FROM sys.index_columns IC2   
    --WHERE IC2.Object_id = object_id('Person.Address') --Comment for all tables  
    GROUP BY IC2.object_id ,IC2.index_id) tmp3 )tmp4   
  ON I.object_id = tmp4.object_id AND I.Index_id = tmp4.index_id  
 JOIN sys.stats ST ON ST.object_id = I.object_id AND ST.stats_id = I.index_id   
 JOIN sys.data_spaces DS ON I.data_space_id=DS.data_space_id   
 JOIN sys.filegroups FG ON I.data_space_id=FG.data_space_id   
 LEFT JOIN (SELECT * FROM (   
    SELECT IC2.object_id , IC2.index_id ,   
        STUFF((SELECT ' , ' + C.name  
    FROM sys.index_columns IC1   
    JOIN Sys.columns C    
       ON C.object_id = IC1.object_id    
       AND C.column_id = IC1.column_id    
       AND IC1.is_included_column = 1   
    WHERE IC1.object_id = IC2.object_id    
       AND IC1.index_id = IC2.index_id    
    GROUP BY IC1.object_id,C.name,index_id   
       FOR XML PATH('')), 1, 2, '') IncludedColumns    
   FROM sys.index_columns IC2    
   --WHERE IC2.Object_id = object_id('Person.Address') --Comment for all tables   
   GROUP BY IC2.object_id ,IC2.index_id) tmp1   
   WHERE IncludedColumns IS NOT NULL ) tmp2    
ON tmp2.object_id = I.object_id AND tmp2.index_id = I.index_id   
WHERE I.is_primary_key = 0 AND I.is_unique_constraint = 0 
AND I.[name] = @index_name

return @Return

end

Sql per un po':

declare @RebuildIndex Table(
    IndexId int identity(1,1),
    IndexName varchar(100),
    TableSchema varchar(50),
    TableName varchar(100),
    Fragmentation decimal(18,2)
)


insert into @RebuildIndex (IndexName,TableSchema,TableName,Fragmentation)
SELECT 
    B.[name] as 'IndexName', 
    Schema_Name(O.[schema_id]) as 'TableSchema',
    OBJECT_NAME(A.[object_id]) as 'TableName',
    A.[avg_fragmentation_in_percent] Fragmentation
FROM sys.dm_db_index_physical_stats(db_id(),NULL,NULL,NULL,'LIMITED') A 
INNER JOIN sys.indexes B ON A.[object_id] = B.[object_id] and A.index_id = B.index_id  
INNER JOIN sys.objects O ON O.[object_id] = B.[object_id]  
 where B.[name] is not null and B.is_primary_key = 0 AND B.is_unique_constraint = 0 and A.[avg_fragmentation_in_percent] >= 5  

--select * from @RebuildIndex

 declare @begin int = 1
 declare @max int
 select @max = Max(IndexId) from @RebuildIndex
 declare @IndexName varchar(100), @TableSchema varchar(50), @TableName varchar(100) , @Fragmentation decimal(18,2)

 while @begin <= @max
 begin

    Select @IndexName = IndexName from @RebuildIndex where IndexId = @begin
    select @TableSchema = TableSchema  from @RebuildIndex where IndexId = @begin
    select @TableName = TableName  from @RebuildIndex where IndexId = @begin 
    select @Fragmentation = Fragmentation  from @RebuildIndex where IndexId = @begin 

    declare @sql nvarchar(max)
    if @Fragmentation < 31
    begin
        set @sql = 'ALTER INDEX ['+@IndexName+'] ON ['+@TableSchema+'].['+@TableName+'] REORGANIZE WITH ( LOB_COMPACTION = ON )'
        print 'Reorganized Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
    end
    else
    begin
        set @sql = (select dbo.GetIndexCreateScript(@IndexName))
        if(@sql is not null)
        begin
            print 'Recreated Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
        end 
        else
        begin
            set @sql = 'ALTER INDEX ['+@IndexName+'] ON ['+@TableSchema+'].['+@TableName+'] REBUILD PARTITION = ALL WITH (ONLINE = ON)'
            print 'Rebuilded Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
        end
    end

    execute(@sql)


    set @begin = @begin+1

end
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top