Pregunta

En el SSW reglas de una mejor Base de datos SQL Server hay un ejemplo de una completa base de datos de plan de mantenimiento: SSW.En el ejemplo se ejecuta Reorganizar Índice y, a continuación, un Índice de Reconstrucción y, a continuación, la Actualización de las Estadísticas.Es allí cualquier punto de todo esto?Pensé que Reorganizar Índice fue rápido pero menos eficaces versión de Reconstruir el Índice?y que vuelva a generar el índice también la actualización de las estadísticas de forma automática (en el índice agrupado por lo menos).

¿Fue útil?

Solución

Haciendo un REORGANIZE y, a continuación, un REBUILD en la misma índices es inútil, ya que cualquier cambio por el REORGANIZE sería perdido por hacer el REBUILD.

Peor que eso es que en el plan de mantenimiento diagrama de SSW, se realiza un SHRINK en primer lugar, que los fragmentos de los índices como un efecto secundario de la forma en que se libera el espacio.A continuación, el REBUILD asigna más espacio para los archivos de base de datos de nuevo como espacio de trabajo durante la REBUILD operación.

  • REORGANIZE es una operación en línea que desfragmenta la hoja de páginas en un clúster o índice no agrupado página por página con poco más de espacio de trabajo.

  • REBUILD es una operación en línea en las ediciones Enterprise, sin conexión en otras ediciones, y se utiliza como parte de la extra de espacio de trabajo de nuevo como el tamaño del índice.Se crea una nueva copia del índice y, a continuación, las gotas de la edad, por lo que deshacerse de la fragmentación.Las estadísticas son recalculadas por defecto como parte de esta operación, pero que puede ser desactivado.

Ver La reorganización y Reconstrucción de Índices para obtener más información.

No uso SHRINK excepto con el TRUNCATEONLY opción e incluso entonces, si el archivo va a crecer de nuevo, entonces usted debe pensar en disco duro si es necesario:

sqlservercentral_SHRINKFILE

Otros consejos

Los reorganizar y reconstruir son cosas diferentes.

Reorganizar:es un defrag para los índices.Toma el índice actual(es) y desfragmenta las páginas existentes.Sin embargo, si las páginas no están en manera contigua, se queda igual que antes.Sólo el contenido de las páginas están cambiando.

Reconstruir:en realidad disminuye el índice y reconstruye a partir de cero.Esto significa que usted conseguirá un completamente nuevo índice, con desfragmentado y páginas contiguas.

Por otra parte, con la reconstrucción puede cambiar de partición o grupos de archivos, pero con reorganizar puede desfragmentar todo el índice, pero también sólo una partición del índice.

Las estadísticas de actualización es automática en los índices agrupados, pero no en los no agrupados queridos.

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

  1. ¿Cuál es el grado de fragmentación?
  2. ¿Cuál es la acción apropiada?Reorganizar o volver a generar?

Como se describe en este artículo http://solutioncenter.apexsql.com/why-when-and-how-to-rebuild-and-reorganize-sql-server-indexes/, y para ayudarle a determinar si debe realizar la reconstrucción del índice de índice o de reorganización, por favor, comprenda los siguientes:

  • La reorganización de índices es un proceso donde el SQL Server pasa a través de índice existente, y lo limpia.Reconstrucción de índices es un pesado proceso donde el índice es eliminado y, a continuación, volver a crear a partir de cero con completamente nueva estructura, libre de todos amontonados fragmentos y vacío espacio de las páginas.

  • Mientras que la reorganización de índices es una pura operación de limpieza que deja de estado del sistema como está, sin bloqueo de salida afectados tablas y vistas, el proceso de reconstrucción bloqueos de tabla afectada para todo el período de reconstrucción, que puede resultar en mucho tiempo abajo de veces que podría no ser aceptable en algunos entornos.Con esto en mente, es claro que la reconstrucción de índices es un proceso con 'más fuerte' solución, pero viene con un precio: la larga posible bloqueos en las tablas indexadas.

Por otro lado, la reorganización de índices es un 'ligero' proceso que va a resolver la fragmentación en un menos de manera eficaz – desde limpiar el índice de siempre ser el segundo de la nueva totalmente hecho a partir de cero.Pero la reorganización índice es mucho mejor desde el punto de vista de la eficiencia, ya que no bloquea afectadas tabla indizada durante el curso de la operación.

El mencionado artículo también se explica cómo reorganizar y reconstruir los índices de uso de SSMS, T-SQL (a reorganizar y reconstrucción de índices en una tabla) y una 3ª parte de la herramienta llamada ApexSQL de Copia de seguridad.

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

Cuando el índice es, en un solo archivo de la reorg y reindex tendrá el mismo resultado final.

Algunas veces la reorg será más rápido, y algunas veces el reindex será más rápido dependiendo de la fragmentación del índice.Al menos fragmentado el índice, a continuación, un reorg será más rápido, el más fragmentado, más lenta es la reorg será, pero el más rápido de un reindex será.

Exactamente lo que Biri dijo.Aquí es cómo me gustaría volver a indexar toda una base de datos:

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

Yo Utilice 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 Trabajo que ejecute este SP cada semana.

Aún mejor es:

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REINDEX'

o

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REORGANIZE'

Mis dos centavos...Este método sigue las especificaciones descritas en la tecnología de la red: 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

He investigado en la web y encontré algunos de los buenos artículos.En el y yo escribimos la función de secuencia de comandos y por debajo del cual es reorganizar, recrear o reconstruir todos los índices en una base de datos.

En primer lugar usted puede necesitar para leer este artículo para entender por qué estamos no sólo recrear todos los índices.

Segundo, necesitamos una función para generar script de creación de índice.Así este artículo pueden ayudar.También voy a compartir el trabajo de la función a continuación.

El último paso de hacer un bucle while para encontrar y organizar todos los índices de la base de datos. Este video es la rejilla 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 mientras:

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top