Devo ridurre il mio database: ho appena liberato molto spazio


35

Questa domanda viene posta in varie forme qui, ma la domanda si riduce a:

So che restringere un database è rischioso. In questo caso, ho rimosso così tanti dati e non li userò mai più.

  • Come posso ridurre il mio database? Quali file posso ridurre?
  • Quali dovrebbero essere le mie considerazioni mentre lo faccio?
  • Dovrei fare qualcosa dopo?
  • E se fosse un database di grandi dimensioni? Posso ridurlo con incrementi più piccoli?

2
Ho lottato con questo qualche tempo fa: dba.stackexchange.com/questions/47310/… Ho cercato di riassumere la mia esperienza nella mia risposta
Csaba Toth,

Risposte:


30

Alcuni avvertimenti iniziali:

  1. È generalmente nota come la peggiore pratica per ridurre mai un database di produzione o un file di dati (i file di registro sono un altro problema di cui parla questa domanda ). Consiglio alle persone di non ridurre i propri database nei post di blog come questo in cui parlo di "dimensionamento corretto" e buona pianificazione. Non sono solo lì ( Paul Randal , Brent Ozar , solo per fornire un altro paio di collegamenti). Ridurre un indice di file di dati o frammenti di database, è lento e laborioso per le tue risorse, può essere un problema per il tuo sistema ed è solo una brutta cosa da fare, in generale
  2. In questo caso, sappiamo tutti che esiste il rischio, siamo pronti ad affrontarlo, ma abbiamo liberato molto spazio di cui sappiamo che non avremo mai più bisogno. Quindi, in questo specifico tipo di caso, il restringimento ha molto senso come una delle nostre opzioni.

Se hai letto delle preoccupazioni e dei rischi e hai ancora bisogno di fare questo restringimento perché hai liberato una notevole quantità di spazio, speriamo che il resto di questa risposta ti aiuti. Ma considera i rischi.

Ci sono due approcci principali che due considerano qui:

1.) Riduci Sì, esegui l'effettivo restringimento : considera di utilizzare DBCC SHRINKFILEinvece di DBCC SHRINKDATABASEavere un maggiore controllo su ciò che si restringe e su come. Ciò causerà sicuramente un certo peggioramento delle prestazioni: si tratta di un'operazione di grandi dimensioni che esegue un sacco di operazioni di I / O. Puoi potenzialmente cavartela con ripetuti restringimenti a una dimensione target che diventa progressivamente più piccola.

Questo è l'esempio "A.)" nel DBCC SHRINKFILElink sopra . In questo esempio un file di dati viene ridotto a dimensioni target di 7 MB. Questo formato è un buon modo per ridursi ripetutamente come consente la finestra dei tempi di inattività. Lo farei nei test sullo sviluppo per vedere come appaiono le prestazioni e quanto basso / alto puoi andare di un incremento e per determinare i tempi previsti nella produzione. Questa è un'operazione online : puoi eseguirla con gli utenti del sistema che accedono al database in fase di riduzione, ma ci sarà un degrado delle prestazioni, quasi garantito. Quindi monitora e guarda e vedi cosa stai facendo al server, scegli una finestra di inattività o un periodo di attività più leggera, idealmente.

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

Ricorda sempre: - ogni volta che riduci frammenti i tuoi indici e dovresti fare una ricostruzione degli indici se intendi ridurti in blocchi per un periodo di tempo prolungato. Ora stai affrontando quel costo ogni volta se non riesci a farlo tutto in una finestra.

2.) Nuovo database : è possibile creare un nuovo database e migrare i dati su di esso. Dovresti eseguire lo scripting del database vuoto e di tutte le sue chiavi, indici, oggetti, processi, funzioni, ecc., Quindi migrare i dati su di esso. Potresti scrivere degli script per questo o potresti usare uno strumento come SQL Data Compare di Red Gate o altri fornitori con strumenti simili. Questo è più lavoro di installazione dalla tua parte, più sviluppo e test e, a seconda del tuo ambiente, può anche far saltare la finestra dei tempi di fermo ma un'opzione da considerare.

Quando sono costretto a ridurre un database Se questo fosse il mio ambiente, cercherei di lasciare una buona quantità di spazio bianco nel file di dati perché mi piace essere un porco del disco e mi piace essere preparato per una crescita futura / imprevista. Quindi vorrei essere a posto di nuovo dando spazio se abbiamo appena cancellato un maggior parte dello spazio, ma non avevo mai fidarsi di quelli che dice "ma non potrà mai crescere" e lasciano ancora un po 'di spazio bianco. Il percorso con cui probabilmente seguirei ( sospiro) è l'approccio restringente se avessi finestre di downtime più piccole e non volessi incorrere nella complessità della creazione di un DB vuoto e della migrazione dei dati su di esso. Quindi lo ridurrei un po 'di volte in modo incrementale (in base a quante volte ho pensato di dover basare sui miei test in sviluppo e sulla dimensione desiderata. Scegliendo progressivamente una dimensione del file più piccola) e poi ricostruire gli indici .. E poi io' non dire mai a nessuno che ho ridotto il mio database ;-)


1
Aggiungerei il caso speciale che se hai eliminato molti dati da un heap (specialmente dalla metà dell'heap) non sarai in grado di recuperare quello spazio fino a quando non aggiungi un indice cluster ad esso (si spera per sempre), e quindi rilasciare l'indice cluster dopo (trasformandolo nuovamente in un heap). Naturalmente se l'heap viene troncato regolarmente, allora non ci sono preoccupazioni. Ma vale ancora la pena menzionare.
Jonathan Fite,

Qualcuno può spiegare le implicazioni di NOTRUNCATE E TRUNCATEONLY, apparentemente quest'ultimo non riordina le pagine e quindi non causa la frammentazione dell'indice?
David Garcia,

4
  1. Come posso ridurre il mio database? Quali file posso ridurre? : È possibile ridurre i file singolarmente con il DBCC SHRINKFILEcomando menzionato. Dipende dal tuo server quanti file contiene il tuo database. Un database semplice ha un file di database e un file di registro delle transazioni.
  2. Quali dovrebbero essere le mie considerazioni mentre lo faccio?: la riduzione influisce sulla frammentazione dell'indice, vedi 3 ° punto. Si noti inoltre che non si desidera ridurre il file del database a una dimensione minima possibile, poiché in un ambiente reale crescerà comunque. Quindi ottimizzerei le dimensioni (nel tuo esempio hai dato 7 megabyte) in modo da lasciare uno spazio libero del 10% -20% all'interno del file del database, perché sarà comunque riempito nell'ambiente di produzione e puoi salvare alcuni cicli di crescita automatica in questo modo. Quindi il numero effettivo richiede un attento calcolo. Si noti inoltre che il "grande spazio libero" eseguito avrebbe gonfiato il file di registro delle transazioni anche più dello spazio guadagnato nel file DB. Inoltre, l'effettivo guadagno di spazio che potresti sperimentare sarà inferiore a quello che ti aspetti matematicamente! Quindi supponiamo che tu abbia liberato matematicamente 12 concerti,
  3. Dovrei fare qualcosa dopo? : Come ho accennato in precedenza, vuoi reindicizzare quegli indici la cui frammentazione è stata distorta a causa delle modifiche di SHRINK. Non ho sperimentato abbastanza se devi fare qualcosa di speciale sulle statistiche delle query.
  4. E se fosse un database di grandi dimensioni? Posso ridurlo con incrementi più piccoli? L'operazione SHRINK può essere interrotta in qualsiasi momento e puoi continuare in seguito. Consiglierei di eseguirlo su un database off-line, se possibile. Interrompendo e contendendosi, sarebbe andato avanti con le stesse dimensioni ridotte. Teoricamente puoi ridurlo in incrementi più piccoli specificando una dimensione target meno stretta invece di 7 megabyte, ma direi che se lo stai eseguendo in produzione, allora provaci. Come vedi ci sono problemi con la frammentazione dell'indice e la possibile crescita del registro delle transazioni. Quindi lo farei solo una volta.

Sappiamo tutti che non è consigliabile fare SHRINK regolarmente comunque. Cerco di escludere tutti gli avvertimenti e le dichiarazioni di non responsabilità che probabilmente conosci comunque. Esegui il backup e, se possibile, non farlo a casa :)

Bonus: nell'ambiente di replica se lo esegui nel database del publisher, non causerà il restringimento dei database degli abbonati (il che potrebbe avere il problema di dimensioni perché sono edizioni Express).

Infine, il mio 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

L'unica variabile in questo è la 14, che può essere ottenuta emettendo select DB_ID('YourDBName'), e lo script presuppone che tu sia interessato solo alle tabelle nello schema dba. *.


2
Per la ricostruzione dell'indice, nota che DBREINDEX è stato deprecato in SQL 2005. Invece dell'enorme script con i cursori, puoi semplicemente usare: EXEC sp_MSForeachtable @ Command1 = "ALTER INDEX ALL ON? REBUILD" Spero che questo aiuti qualcuno.
KISS il

2

Hai sentito tutti gli avvertimenti sulla riduzione dei database e sono tutti veri. Frammenterà i tuoi indici ed è in generale, confondere il tuo database e non dovrebbe essere fatto su un sistema di produzione.

Ma generalmente lo faccio su base settimanale quando ripristino un backup sulla mia workstation a causa dello spazio sul mio disco SSD. Intendiamoci, non ho scritto questa sceneggiatura ma l'ho trovata anni fa. Su altri database [250 GB], ho creato un pacchetto SSIS che trasferirà le tabelle di cui ho bisogno e quindi ricreare gli indici per quella sensazione di indice così fresca.

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

1

Questo preventivo è direttamente di Microsoft (si applica alle versioni 2008-2016) e fornisce indicazioni su se / quando e come utilizzare il DBCC SHRINKFILEcomando.

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

Migliori pratiche

Considerare le seguenti informazioni quando si prevede di ridurre un file:

  • Un'operazione di compattazione è più efficace dopo un'operazione che crea molto spazio inutilizzato, ad esempio una tabella troncata o un'operazione di tabella a discesa.
  • La maggior parte dei database richiede che sia disponibile dello spazio libero per le normali operazioni quotidiane. Se si restringe ripetutamente un database e si nota che le dimensioni del database aumentano di nuovo, ciò indica che lo spazio che è stato ridotto è necessario per le normali operazioni. In questi casi, ridurre ripetutamente il database è un'operazione sprecata.
  • Un'operazione di compattazione non preserva lo stato di frammentazione degli indici nel database e generalmente aumenta la frammentazione a un livello. Questo è un altro motivo per non ridurre ripetutamente il database.
  • Riduci più file nello stesso database in sequenza anziché in concomitanza. La contesa sulle tabelle di sistema può causare ritardi dovuti al blocco.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.