Preciso reduzir meu banco de dados - acabei de liberar muito espaço

35

Esta pergunta é feita de várias formas aqui, mas a questão se resume a:

Eu sei que diminuir um banco de dados é arriscado. Nesse caso, removi muitos dados e nunca os utilizarei novamente.

  • Como posso reduzir meu banco de dados? Quais arquivos eu encolho?
  • Quais devem ser minhas considerações ao fazer isso?
  • Devo fazer alguma coisa depois?
  • E se for um banco de dados grande? Posso encolhê-lo em incrementos menores?
Mike Walsh
fonte
2
Lutei com isso há algum tempo: dba.stackexchange.com/questions/47310/... Tentei resumir a minha experiência na minha resposta
Csaba Toth

Respostas:

30

Algumas advertências iniciais:

  1. Geralmente, é uma prática recomendada reduzir sempre um banco de dados ou arquivo de dados de produção (os arquivos de log são outro problema mencionado nesta pergunta ). Aconselho as pessoas a não encolherem seus bancos de dados em posts como este, onde falo sobre "dimensionamento correto" e bom planejamento. Não estou sozinho lá ( Paul Randal , Brent Ozar , apenas para fornecer mais alguns links). Diminuir um arquivo de dados ou índices de fragmentos de banco de dados, é lento e trabalhoso em seus recursos, pode ser um dreno no sistema e é apenas uma coisa ruim a fazer, geralmente
  2. Nesse caso, todos sabemos que o risco existe, estamos preparados para lidar com ele, mas liberamos muito espaço que sabemos que nunca mais precisaremos. Portanto, nesse tipo específico de caso, a redução faz muito sentido como uma de nossas opções.

Se você leu sobre as preocupações e os riscos e ainda precisa diminuir, porque liberou uma quantidade significativa de espaço, espero que o restante desta resposta o ajude. Mas considere os riscos.

Existem duas abordagens principais que duas consideram aqui:

1.) Encolher Sim, faça o encolhimento real - considere usar em DBCC SHRINKFILEvez de DBCC SHRINKDATABASE, você tem mais controle sobre o que encolhe e como. Isso vai causar alguma degradação do desempenho com certeza - é uma grande operação fazendo um monte de IO. Você pode potencialmente fugir com psiquiatras repetidas para um tamanho alvo que se torna progressivamente menor.

Este é o exemplo "A.)" no DBCC SHRINKFILElink acima . Um arquivo de dados está sendo reduzido para o tamanho de destino de 7 MB neste exemplo. Esse formato é uma boa maneira de encolher repetidamente, conforme sua janela de tempo de inatividade permite. Eu faria isso nos testes de desenvolvimento para ver como o desempenho parece e quão baixo / alto você pode obter um incremento e determinar o tempo esperado na produção. Essa é uma operação on - line - você pode executá-la com usuários no sistema que acessam o banco de dados que estão sendo reduzidos, mas haverá degradação no desempenho, quase garantida. Portanto, monitore e observe e veja o que você está fazendo no servidor, escolha uma janela de tempo de inatividade ou um período de atividade mais leve, idealmente.

USE YourDatabase;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO

Lembre-se sempre: - toda vez que você encolhe, fragmenta seus índices e deve reconstruir o índice se quiser encolher pedaços durante um período prolongado de tempo. Agora você está pagando um custo cada vez que não consegue fazer tudo em uma janela.

2.) Novo banco de dados - você pode criar um novo banco de dados e migrar dados para ele. Você teria que criar um script para o banco de dados vazio e todas as suas chaves, índices, objetos, procs, funções etc. e depois migrar dados para ele. Você pode escrever scripts para isso ou usar uma ferramenta como o SQL Data Compare do Red Gate ou outros fornecedores com ferramentas semelhantes. Isso é mais trabalho de configuração do seu lado, mais desenvolvimento e teste e, dependendo do seu ambiente, também pode explodir sua janela de tempo de inatividade, mas é uma opção a considerar.

Quando sou forçado a encolher um banco de dados Se esse fosse o meu ambiente, procuraria deixar uma quantidade razoável de espaço em branco no arquivo de dados porque gosto de ser um porco e gostaria de estar preparado para um crescimento futuro / inesperado. Então, eu ficaria bem em devolver o espaço se apenas deletássemos a maior parte do espaço, mas eu nunca confiaria naqueles que dizem "mas isso nunca voltará a crescer" e ainda deixará algum espaço em branco. A rota que eu provavelmente seguiria ( suspiro) é a abordagem de redução, se eu tivesse janelas menores de inatividade e não quisesse incorrer na complexidade de criar um banco de dados vazio e migrar dados para ele. Então, eu o reduzia um monte de vezes de forma incremental (com base em quantas vezes eu pensei que precisava basear nos meus testes no dev e no tamanho desejado. Escolhendo progressivamente um tamanho de arquivo menor) e depois reconstruí os índices. E então eu ' nunca disse a ninguém que encolhi meu banco de dados ;-)

Mike Walsh
fonte
11
Eu acrescentaria o caso especial de que, se você excluiu muitos dados de um heap (especialmente no meio do heap), não poderá recuperar esse espaço até adicionar um índice clusterizado (espero que seja para sempre), e, em seguida, solte o índice clusterizado depois (transformando-o novamente em um heap). Obviamente, se o heap for truncado regularmente, não haverá preocupações. Mas ainda vale a pena mencionar.
Jonathan Fite
Alguém pode explicar a implicação de NOTRUNCATE AND TRUNCATEONLY, aparentemente o último não reorganiza as páginas e, portanto, não causa fragmentação do índice?
David Garcia
4
  1. Como posso reduzir meu banco de dados? Quais arquivos eu encolho? : Você pode reduzir os arquivos individualmente pelo DBCC SHRINKFILEcomando mencionado. Depende do servidor quantos arquivos seu banco de dados consiste. Um banco de dados simples possui um arquivo de banco de dados e um arquivo de log de transações.
  2. Quais devem ser minhas considerações ao fazer isso?: o psiquiatra afeta a fragmentação do índice, consulte o terceiro ponto. Observe também que você não deseja reduzir o arquivo do banco de dados para um tamanho mínimo possível, porque, em um ambiente do mundo real, ele aumentará de qualquer maneira. Então, eu ajustaria o tamanho (no seu exemplo, você forneceu 7 megabytes) de maneira a deixar 10% a 20% de espaço livre no arquivo do banco de dados, porque ele será preenchido de qualquer maneira no ambiente de produção e você poderá salve alguns ciclos de crescimento automático dessa maneira. Portanto, o número real precisa de um cálculo cuidadoso. Observe também que o "grande espaço livre" que você executou aumentaria o arquivo de log de transações ainda mais do que o espaço que você ganha no arquivo DB. Além disso, o ganho real de espaço que você pode experimentar será menor do que o que você espera matematicamente! Então, digamos que você matematicamente liberou 12 shows,
  3. Devo fazer alguma coisa depois? : Como mencionei anteriormente, você deseja reindexar os índices cuja fragmentação foi distorcida como resultado das alterações do SHRINK. Não experimentei o suficiente se você precisar fazer algo especial sobre estatísticas de consulta.
  4. E se for um banco de dados grande? Posso encolhê-lo em incrementos menores? A operação SHRINK pode ser interrompida a qualquer momento e você pode continuar mais tarde. Eu aconselho a executá-lo em um banco de dados off-line, se possível. Ao interromper e contuniung, iria avançar o mesmo tamanho de contração. Teoricamente, você pode reduzir em incrementos menores especificando um tamanho de destino menos restrito, em vez de 7 megabytes, mas eu diria que, se você o estiver executando em produção, basta tentar. Como você vê, há problemas com a fragmentação do índice e possível crescimento do log de transações. Então, eu passaria por isso apenas uma vez.

Todos sabemos que não é aconselhável fazer SHRINK regularmente de qualquer maneira. Tento deixar de fora todos os avisos e isenções de responsabilidade que você provavelmente conhece. Faça backup e não faça isso em casa, se possível :)

Bônus: no ambiente de replicação, se você fizer isso no banco de dados do editor, isso não fará com que os bancos de dados do assinante encolhem (o que pode ter um problema de tamanho, porque são edições Express).

Por fim, meu script reindex:

USE YourDBName

DECLARE @TbName VARCHAR(255)
DECLARE @FullTbName VARCHAR(255)
DECLARE @IxName VARCHAR(255)
DECLARE myCursor CURSOR FOR
    SELECT OBJECT_NAME(dmi.object_id) AS TableName,i.name AS IndexName
    FROM sys.dm_db_index_physical_stats(14, NULL, NULL, NULL , 'LIMITED') dmi
    JOIN  sys.indexes i on dmi.object_id = i.object_id and dmi.index_id = i.index_id
    WHERE avg_fragmentation_in_percent > 30
    ORDER BY avg_fragmentation_in_percent
OPEN myCursor
FETCH NEXT FROM myCursor INTO @TbName, @ixName
WHILE @@FETCH_STATUS = 0
BEGIN
    IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'dba' AND TABLE_NAME = @TbName)
BEGIN
        SET @FullTbName = 'dba.' + @TbName
        IF (@ixName IS NULL)
        BEGIN
            PRINT 'Reindexing Table ' + @FullTbName
            DBCC DBREINDEX(@FullTbName, '', 0)
        END
        ELSE
        BEGIN
             PRINT 'Reindexing Table ' + @FullTbName + ', Index ' + @IxName
             DBCC DBREINDEX(@FullTbName, @IxName, 0)
        END
    END
    FETCH NEXT FROM myCursor INTO @TbName, @ixName
END
CLOSE myCursor
DEALLOCATE myCursor

A única variável nisso é a 14, que pode ser obtida emitindo select DB_ID('YourDBName'), e o script assume que você está interessado apenas nas tabelas no esquema dba. *.

Csaba Toth
fonte
2
Para a reconstrução do índice, observe que DBREINDEX foi preterido no SQL 2005. Em vez do script enorme com cursores, você pode simplesmente usar: EXEC sp_MSForeachtable @ Command1 = "ALTER INDEX ALL ON? REBUILD" Espero que isso ajude alguém.
KISS
2

Você ouviu todos os avisos sobre a redução de bancos de dados e todos são verdadeiros. Ele fragmentará seus índices e, em geral, atrapalha seu banco de dados e não deve ser feito em um sistema de produção.

Porém, geralmente faço isso semanalmente quando restauro um backup na minha estação de trabalho devido ao espaço na minha unidade SSD. Veja bem, eu não escrevi esse script, mas o encontrei anos atrás. Em outros bancos de dados [250 GB], criei um pacote SSIS que transferirá as tabelas necessárias e, em seguida, recriará os índices para uma sensação de índice tão recente.

DECLARE @DBFileName SYSNAME

DECLARE @TargetFreeMB INT

DECLARE @ShrinkIncrementMB INT

SET @DBFileName = 'Set Name of Database file to shrink'

-- Set Desired file free space in MB after shrink

SET @TargetFreeMB = 500
-- Set Increment to shrink file by in MB
SET @ShrinkIncrementMB = 100

SELECT [FileSizeMB] = convert(NUMERIC(10, 2),
round(a.size / 128., 2)),

[UsedSpaceMB] = convert(NUMERIC(10, 2),

round(fileproperty(a.NAME, 'SpaceUsed') / 128., 2)),

[UnusedSpaceMB] = convert(NUMERIC(10, 2),

round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2)),

[DBFileName] = a.NAME

FROM sysfiles a

DECLARE @sql VARCHAR(8000)
DECLARE @SizeMB INT
DECLARE @UsedMB INT

SELECT @SizeMB = size / 128.
FROM sysfiles
WHERE NAME = @DBFileName

SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

SELECT [StartFileSize] = @SizeMB
    ,[StartUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

WHILE @SizeMB > @UsedMB + @TargetFreeMB + @ShrinkIncrementMB

BEGIN
    SET @sql = 'dbcc shrinkfile ( ' + @DBFileName + ', ' + convert(VARCHAR(20), @SizeMB - @ShrinkIncrementMB) + ' ) '

    PRINT 'Start ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    EXEC (@sql)

    PRINT 'Done ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    SELECT @SizeMB = size / 128.
    FROM sysfiles
    WHERE NAME = @DBFileName

    SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

    SELECT [FileSize] = @SizeMB
        ,[UsedSpace] = @UsedMB
        ,[DBFileName] = @DBFileName
END

SELECT [EndFileSize] = @SizeMB
    ,[EndUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

SELECT [FileSizeMB] = convert(NUMERIC(10, 2), round(a.size / 128., 2))

    ,[UsedSpaceMB] = convert(NUMERIC(10, 2), round(fileproperty a.NAME, 'SpaceUsed') / 128., 2))

,[UnusedSpaceMB] = convert(NUMERIC(10, 2), round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2))

,[DBFileName] = a.NAME

FROM sysfiles a
user1207758
fonte
1

Esta citação abaixo é diretamente da Microsoft (aplica-se às versões 2008-2016) e fornece orientações sobre se / quando e como você deve usar o DBCC SHRINKFILEcomando.

https://msdn.microsoft.com/en-us/library/ms189493.aspx

Melhores práticas

Considere as seguintes informações ao planejar reduzir um arquivo:

  • Uma operação de redução é mais eficaz após uma operação que cria muito espaço não utilizado, como uma tabela truncada ou uma operação de remoção da tabela.
  • A maioria dos bancos de dados exige algum espaço livre disponível para operações diárias regulares. Se você reduzir um banco de dados repetidamente e perceber que o tamanho do banco de dados aumenta novamente, isso indica que o espaço que foi reduzido é necessário para operações regulares. Nesses casos, reduzir repetidamente o banco de dados é uma operação desperdiçada.
  • Uma operação de redução não preserva o estado de fragmentação dos índices no banco de dados e geralmente aumenta a fragmentação em um grau. Esse é outro motivo para não reduzir repetidamente o banco de dados.
  • Reduza vários arquivos no mesmo banco de dados sequencialmente, em vez de simultaneamente. A contenção nas tabelas do sistema pode causar atrasos devido ao bloqueio.
g2server
fonte