🚀 Shrink de Datafiles no SQL Server: Redução Controlada em Lotes com Monitoramento em Tempo Real
- CloudDB

- há 5 dias
- 3 min de leitura
Quem administra bancos de dados SQL Server sabe que executar um simples DBCC SHRINKFILE em arquivos gigantescos pode ser uma verdadeira dor de cabeça. Fazer essa redução de uma vez só costuma gerar problemas severos de concorrência e uma sobrecarga brutal de I/O (leitura e gravação no disco), o que pode acabar travando a sua aplicação.
Para resolver esse problema, a melhor estratégia é "fatiar" essa tarefa. Disponibilizamos abaixo um pacote de scripts para você realizar o shrink de forma inteligente, segura e monitorada.
🌟 O Diferencial do Nosso Script
Em vez de usar a abordagem tradicional, onde o DBA precisa calcular e "adivinhar" o tamanho final ideal do arquivo, nosso script inverte a lógica para facilitar a sua vida:
Foco na Redução: Você informa apenas quantos Megabytes deseja liberar. O script calcula o resto.
Trava de Segurança: O código lê o espaço real ocupado pelos dados. Se você pedir para reduzir 50 GB, mas houver apenas 10 GB livres, a meta é ajustada automaticamente para não interromper ou corromper a base.
Pausas Estratégicas (I/O): A redução é feita em pequenos lotes (chunks de 2 GB). Entre cada lote, o script pausa por 5 segundos, dando um "respiro" para o disco do servidor.
🛠️ Script 1: Executando o Shrink Inteligente
Atenção: Antes de executar, lembre-se de substituir as marcações genéricas [NOMEDOBANCO] e N'NOMEDODATAFILE' pelo nome do seu banco e pelo nome lógico do seu datafile, respectivamente.
SQL
USE [NOMEDOBANCO];
GO
DECLARE @FileName SYSNAME = N'NOMEDODATAFILE'; -- Nome do datafile a ser feito o shrink
DECLARE @ReduceMB INT = 50000; -- Quantidade em MB para reduzir (Ex: 50000). Coloque 0 para limpar tudo.
DECLARE @ChunkMB INT = 2048; -- Reduzir de 2048 em 2048 MB (2 GB por vez)
DECLARE @InitialSizeMB INT;
DECLARE @UsedSpaceMB INT;
DECLARE @TargetSizeMB INT;
DECLARE @CurrentSizeMB INT;
DECLARE @TotalSteps INT;
DECLARE @CurrentStep INT = 1;
DECLARE @Message NVARCHAR(2048);
-- 1. Obtém o tamanho inicial em MB
SELECT @InitialSizeMB = size * 8 / 1024
FROM sys.database_files
WHERE name = @FileName;
-- Validação de Nome Lógico
IF @InitialSizeMB IS NULL
BEGIN
RAISERROR('ERRO FATAL: O arquivo lógico "%s" não foi encontrado. Verifique o nome correto usando sp_helpfile.', 16, 1, @FileName) WITH NOWAIT;
RETURN; -- Aborta o script
END
-- 2. Obtém o espaço real utilizado pelos dados no arquivo (em MB)
SET @UsedSpaceMB = CAST(FILEPROPERTY(@FileName, 'SpaceUsed') AS INT) * 8 / 1024;
-- 3. Define a meta de tamanho
IF @ReduceMB = 0
BEGIN
SET @TargetSizeMB = @UsedSpaceMB;
SET @Message = FORMATMESSAGE('Modo TRUNCATE ativado. O alvo será o tamanho mínimo possível: %d MB.', @TargetSizeMB);
RAISERROR(@Message, 10, 1) WITH NOWAIT;
END
ELSE
BEGIN
SET @TargetSizeMB = @InitialSizeMB - @ReduceMB;
-- Trava de segurança
IF @TargetSizeMB < @UsedSpaceMB
BEGIN
SET @TargetSizeMB = @UsedSpaceMB;
RAISERROR('ATENÇÃO: A redução solicitada é maior que o espaço livre! Ajustando a meta para proteger os dados.', 10, 1) WITH NOWAIT;
END
END
-- ==========================================
-- PAINEL DE DIAGNÓSTICO (Mostra na tela)
-- ==========================================
RAISERROR('--------------------------------------------------', 10, 1) WITH NOWAIT;
SET @Message = FORMATMESSAGE('Tamanho Atual do Arquivo : %d MB', @InitialSizeMB);
RAISERROR(@Message, 10, 1) WITH NOWAIT;
SET @Message = FORMATMESSAGE('Espaço Ocupado por Dados : %d MB (Não pode ser reduzido além disso)', @UsedSpaceMB);
RAISERROR(@Message, 10, 1) WITH NOWAIT;
SET @Message = FORMATMESSAGE('Meta Final do Shrink : %d MB', @TargetSizeMB);
RAISERROR(@Message, 10, 1) WITH NOWAIT;
RAISERROR('--------------------------------------------------', 10, 1) WITH NOWAIT;
SET @CurrentSizeMB = @InitialSizeMB;
-- 4. Inicia o Loop de Shrink
IF @InitialSizeMB > @TargetSizeMB
BEGIN
SET @TotalSteps = CEILING(CAST(@InitialSizeMB - @TargetSizeMB AS FLOAT) / @ChunkMB);
WHILE @CurrentSizeMB > @TargetSizeMB
BEGIN
SET @CurrentSizeMB = @CurrentSizeMB - @ChunkMB;
IF @CurrentSizeMB < @TargetSizeMB
SET @CurrentSizeMB = @TargetSizeMB;
SET @Message = FORMATMESSAGE('Shrink %d/%d - Reduzindo lote... Meta deste lote: %d MB', @CurrentStep, @TotalSteps, @CurrentSizeMB);
RAISERROR(@Message, 10, 1) WITH NOWAIT;
-- Executa o shrink
DBCC SHRINKFILE (@FileName, @CurrentSizeMB);
-- Verifica o tamanho real
SELECT @CurrentSizeMB = size * 8 / 1024
FROM sys.database_files
WHERE name = @FileName;
SET @CurrentStep = @CurrentStep + 1;
WAITFOR DELAY '00:00:05'; -- Pausa para aliviar I/O
END
RAISERROR('Shrink finalizado com sucesso!', 10, 1) WITH NOWAIT;
END
ELSE
BEGIN
RAISERROR('O arquivo já está no tamanho alvo ou não tem mais espaço em branco (livre) para encolher.', 10, 1) WITH NOWAIT;
END
GO
📊 Script 2: Acompanhando o Progresso em Tempo Real
Como o processo de shrink fragmentado pode levar algum tempo, é crucial saber o que está acontecendo nos bastidores. Abra uma nova aba (sessão) no seu SQL Server Management Studio e rode a consulta abaixo.
Ela traduzirá o processamento interno em métricas fáceis de ler, mostrando a porcentagem de conclusão e os minutos restantes para o lote atual finalizar:
SQL
-- Script para acompanhar o andamento de cada shrink
SELECT
session_id,
command,
status,
percent_complete AS [% Concluída do Lote Atual],
estimated_completion_time / 1000 / 60 AS [Minutos Restantes (Lote Atual)],
total_elapsed_time / 1000 / 60 AS [Minutos Decorridos]
FROM sys.dm_exec_requests
WHERE command IN ('DbccSpaceReclaim', 'DbccFilesCompact')
OR command LIKE 'DBCC%';


Comentários