sexta-feira, 18 de junho de 2010

Rotina para identificação e desfragmentação automática das estruturas de um database.


Boa tarde!!!

Este post visa mostrar a vocês uma rotina para identificação das estruturas (tabelas e seus índices) que estão fragmentados de acordo com métricas previamente definidas e, automaticamente, reorganiza ou reconstrói os índices das tabelas.

Esta rotina recupera todos os índices que estão com o LogicalFragmentation acima de 20% ou o menor ScanDensity abaixo de 80% e realiza a reorganização destes.

Para os casos mais absurdos, que ultrapassem o limiar de 50%, o REBUILD do índice será realizado, com isso, a estrutura será refeita de forma organizada.

Uma observação importante é que essa operação poderá deixar a base lenta e gerar bloqueios para reorganização (REORGANIZE) / reconstrução (REBUILD). Vale ressaltar que o script poderá ser utilizado para as versões 2005 e 2008 do MS SQL Server.

Segue o script:

--Início do Script

use <nome-do-banco>

declare @maxLogicalFrag tinyint,

           @minScanDensity tinyint

--Métricas previamente definidas para os limiares de fragmentação e ScanDensity

set @maxLogicalFrag = 20

set @minScanDensity = 80

--Estrutura auxiliar que será criada no TEMPDB para guardar informações estatísticas das tabelas

if object_id('tempdb..#showcontig') is not null

       drop table #showcontig



create table #showcontig (

       ObjectName sysname,

       ObjectId int,

       IndexName sysname,

       IndexId int,

       Level int,

       Pages int,

       Rows int,

       MinimumRecordSize int,

       MaximumRecordSize int,

       AverageRecordSize int,

       ForwardedRecords int,

       Extents int,

       ExtentSwitches int,

       AverageFreeBytes int,

       AveragePageDensity int,

       ScanDensity int,

       BestCount int,

       ActualCount int,

       LogicalFragmentation int,

       ExtentFragmentation int

)

declare @nome as sysname

         , @str as varchar(512)

--Seleciona todas as tabelas do database que não são do sistema.

declare cTables cursor for

select name

from sys.tables

where name not like 'sys%'

--Loop para coleta de informações estatísticas sobre as tabelas e seus respectivos índices.

open cTables

FETCH NEXT FROM cTables INTO @nome

while @@fetch_status = 0 begin

       set @str = 'dbcc showcontig(' + @nome + ') with all_indexes, fast, tableresults'

       insert into #showcontig

       exec (@str)

       FETCH NEXT FROM cTables INTO @nome

end

close cTables

deallocate cTables

declare @ObjectName sysname, @IndexId int, @IndexName sysname, @cmd varchar(512)

declare cIndices cursor for

--Seleciona os índices para realizar o reorganize

select ObjectName

       , IndexId

       , IndexName

       , 'alter index ' + IndexName + ' ON ' + ObjectName + ' REORGANIZE;' as command

from #showcontig

where (ScanDensity <= @minScanDensity

          or LogicalFragmentation >= @maxLogicalFrag)

   and (ScanDensity > 50 or

           LogicalFragmentation < 50)

union

--Seleciona os índices para realizar o rebuild

select ObjectName

       , IndexId

       , IndexName

       , 'alter index ' + IndexName + ' ON ' + ObjectName + ' REBUILD;' as command

from #showcontig

where (ScanDensity <= @minScanDensity

      or LogicalFragmentation >= @maxLogicalFrag)

    and (ScanDensity <= 50 and

            LogicalFragmentation >= 50)

order by ObjectName, IndexId

--Loop para execução dos comandos gerados para a reorganização dos índices selecionados.

Open cIndices

FETCH NEXT FROM cIndices INTO @ObjectName, @IndexId, @IndexName, @cmd

while @@fetch_status = 0 begin

       exec (@cmd)

       FETCH NEXT FROM cIndices INTO @ObjectName, @IndexId, @IndexName, @cmd

end

close cIndices

deallocate cIndices

--Fim do Script

Um comentário:

  1. Boa dica, David. Gosto de utilizar o seguinte SELECT para recuperar a fragmentação dos índices do SQL Server a partir da versão 2005:

    SELECT si.[name] as index_name
    , sdm.avg_fragmentation_in_percent
    , so.[name] as table_name
    FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL) sdm
    JOIN sys.indexes si on sdm.object_id = si.object_id and si.index_id = sdm.index_id
    JOIN sys.objects so on so.object_id = si.object_id

    Utilizo o resultado desse select junto com um outro script para ai sim efetuar um REORGANIZE/REBUILD nos índices.

    ResponderExcluir