2008-08-11 36 views
32

En las reglas de SSW para una mejor base de datos de SQL Server hay un ejemplo de un plan de mantenimiento de base de datos completo: SSW. En el ejemplo, ejecutan un Reorganize Index y luego un Rebuild Index y luego Update Statistics. ¿Hay algún punto para esto? Pensé que reorganizar Index era una versión rápida pero menos efectiva de Rebuild Index? y que una reconstrucción de índice también actualizaría las estadísticas automáticamente (al menos en el índice agrupado).Reorganizar índice vs Reconstruir índice en el plan de mantenimiento de servidor SQL

Respuesta

16

Haciendo un REORGANIZE y luego un REBUILD en los mismos índices no tiene sentido, ya que cualquier cambio de la REORGANIZE se perderían haciendo lo REBUILD.

Peor que eso es que en el diagrama de plan de mantenimiento de SSW, realiza primero un SHRINK, que fragmenta los índices como un efecto secundario de la forma en que libera espacio. Luego, el REBUILD asigna más espacio a los archivos de la base de datos como espacio de trabajo durante la operación REBUILD.

  • REORGANIZE es una operación en línea que desfragmenta páginas de hoja en una página de índice agrupado o no agrupado por página utilizando poco espacio de trabajo adicional.

  • REBUILD es una operación en línea en ediciones Enterprise, sin conexión en otras ediciones, y utiliza tanto espacio de trabajo adicional de nuevo como el tamaño del índice. Crea una nueva copia del índice y luego descarta la anterior, eliminando así la fragmentación. Las estadísticas se vuelven a calcular de manera predeterminada como parte de esta operación, pero se pueden deshabilitar.

Consulte Reorganizing and Rebuilding Indexes para obtener más información.

No utilice SHRINK, excepto con la opción TRUNCATEONLY e incluso entonces si el archivo volverá a crecer entonces debería pensar seriamente en cuanto a si es necesario:

sqlservercentral_SHRINKFILE

+0

¡Es increíble cuántas "autoridades" en línea son totalmente incorrectas y engañosas, es decir, sugiriendo que debe hacer una reducción en una base de datos! –

30

La reorganización y la reconstrucción son cosas diferentes.

Reorganizar: es una desfragmentación para los índices. Toma los índices existentes y defragmenta las páginas existentes. Sin embargo, si las páginas no están contiguas, se mantienen como antes. Solo el contenido de las páginas está cambiando.

Reconstrucción: en realidad, se quita el índice y se reconstruye desde cero. Significa que obtendrá un índice completamente nuevo, con páginas desfragmentadas y contiguas.

Además, con la reconstrucción puede cambiar las particiones o los grupos de archivos, pero con reorganizar puede desfragmentar no solo todo el índice, sino también una sola partición del índice.

Las estadísticas de actualización son automáticas en los índices agrupados, pero no en los no agrupados.

+1

Correcto, pero ¿hay algún uso para tener una reorganización y una reconstrucción en el mismo sub plan de mantenimiento? – codeulike

+2

En realidad, de acuerdo con Books Online http://msdn.microsoft.com/en-us/library/ms189858.aspx Reorg reorganiza las páginas para hacerlas físicamente contiguas. Aquí está la cita exacta: "La reorganización de un índice desfragmenta el nivel hoja de índices agrupados y no agrupados en tablas y vistas reordenando físicamente las páginas de nivel hoja para que coincida con el orden lógico (de izquierda a derecha) de los nodos hoja. para mejorar el rendimiento del análisis de índice. El índice se reorganiza dentro de las páginas existentes asignadas, no se asignan páginas nuevas ". –

+2

@ MichaelK.Campbell: Su cita fue tomada un poco fuera de contexto. Mientras ReOrg volverá a ordenar las páginas, SÓLO las reordena en el nivel más bajo que los nodos de niveles intermedios señalan a ellas. Después de reordenar, no se garantiza que todas las páginas de todo el índice sean contiguas. Aquí hay una mejor explicación: http://dba.stackexchange.com/a/36817/6816 – MikeTeeVee

7

dijo exactamente lo que Biri dijo. Aquí es cómo iba a indexar una base de datos completa:

10

Cuando se realiza una reorganización de un índice, si el índice se extiende a través de dos o más archivos físicos los datos sólo serán defragged dentro del archivo de datos. Las páginas no se mueven de un archivo de datos a otro.

Cuando el índice está en un solo archivo, la reorganización y reindex tendrán el mismo resultado final.

Algunas veces la reorganización será más rápida, y algunas veces el reindexamiento será más rápido dependiendo de qué tan fragmentado sea el índice. Mientras menos fragmentado sea el índice, una reorganización será más rápida, cuanto más fragmentada, más lenta será la reorganización, pero más rápido será un reindex.

3

Aún mejor es:

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REINDEX' 

o

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REORGANIZE' 
5

Yo uso este 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 

y crear un puesto de trabajo que ejecute este SP todas las semanas.

0

Mis dos centavos ... Este método sigue la especificación se indica en la red de tecnología: 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 
0

He investigado en la web y encontré algunos de los buenos artículos. En el y escribí la función y el script a continuación que reorganiza, recrea o reconstruye todos los índices en una base de datos.

Primero debe leer this article para comprender por qué no solo recreamos todos los índices.

En segundo lugar, necesitamos una función para crear el script de creación para el índice. Entonces this article puede ayudar. También estoy compartiendo la función de trabajo a continuación.

Último paso haciendo un ciclo while para encontrar y organizar todos los índices en la base de datos. This video es un buen ejemplo para hacer esto.

Función:

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 para rato:

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 ['[email protected]+'] ON ['[email protected]+'].['[email protected]+'] 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 ['[email protected]+'] ON ['[email protected]+'].['[email protected]+'] 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 
21

Antes de considerar el mantenimiento de índices, es importante responder a dos cuestiones principales:

  1. ¿Cuál es el grado de ¿fragmentación?
  2. ¿Cuál es la acción adecuada? Reorganizar o reconstruir?

Como se describe en este artículo http://solutioncenter.apexsql.com/why-when-and-how-to-rebuild-and-reorganize-sql-server-indexes/, y para ayudar a determinar si se debe realizar la reconstrucción de índices o reorganización de índices, por favor entender lo siguiente:

  • Índice de reorganización es un proceso donde va el SQL Server a través del índice existente, y lo limpia. La reconstrucción de índices es un proceso de alta resistencia en el que se elimina el índice y luego se recrea desde cero con una estructura completamente nueva, libre de todos los fragmentos acumulados y las páginas de espacio vacío.

  • Mientras que la reorganización de índice es una operación de limpieza pura que deja el estado del sistema como está sin bloquear las tablas y vistas afectadas, el proceso de reconstrucción bloquea la tabla afectada durante todo el período de reconstrucción, lo que puede provocar tiempos de inactividad prolongados. no podría ser aceptable en algunos entornos. Teniendo esto en cuenta, está claro que la reconstrucción del índice es un proceso con una solución "más sólida", pero tiene un precio: posibles bloqueos largos en las tablas indexadas afectadas.

Por otro lado, el índice de reorganización es un proceso ‘ligera’ que va a resolver la fragmentación de una manera menos eficaz - ya que el índice limpiado siempre será la segunda a la nueva totalmente hecha a partir de cero. Pero reorganizar el índice es mucho mejor desde el punto de vista de la eficiencia, ya que no bloquea la tabla indexada afectada durante el curso de la operación.

El artículo mencionado anteriormente también explica cómo reorganizar y reconstruir índices utilizando SSMS, T-SQL (para reorganizar/reconstruir índices en una tabla) y una herramienta de terceros llamada ApexSQL Backup.

Cuestiones relacionadas