2013-11-26 5 views
13

Ho un database 21 Gb; 20 Gb di loro sono file (FileStream) e ho eliminato tutti i file dalla tabella, ma quando faccio un backup il file di backup ancora 21 GB.Avanzamento per DBCC SHRINKFILE

Per risolvere questo problema sono diventato l'idea "liberare lo spazio inutilizzato".

Così sto cercando di compattare mio database come il seguente:

USE Db; 
GO 
-- Truncate the log by changing the database recovery model to SIMPLE. 
ALTER DATABASE Db 
SET RECOVERY SIMPLE; 
GO 
-- Shrink the truncated log file to 1 MB. 
DBCC SHRINKFILE (Db, 100); 
GO 
-- Reset the database recovery model. 
ALTER DATABASE Db 
SET RECOVERY FULL; 
GO 

SELECT file_id, name 
FROM sys.database_files; 
GO 
DBCC SHRINKFILE (1, TRUNCATEONLY); 

Se faccio un backup per il database dopo XX minuti, quindi la dimensione del file di backup è di 1 Gb in questo modo, io può vedere che lo spazio non utilizzato è stato pulito con successo. In altre parole, il codice Sql sopra riportato funziona correttamente (Database dopo XX minuti è schrunk).


Il problema ho bisogno di aspettare fino a questa query (operazione Shrinking) è finito in modo che sto cercando di fare quanto segue:

SELECT percent_complete, start_time, status, command, estimated_completion_time, cpu_time, total_elapsed_time 
FROM sys.dm_exec_requests 

non riesco a trovare alcuna informazione circa la SHRINKFILE comando nei risultati della query precedente.

enter image description here


ho fatto qualcosa di sbagliato? perché non riesco a vedere l'andamento delle operazioni di riduzione dei DB?

E la mia quesiton principale è: come posso aspettare fino a quando lo SHRINKFILE è finito? Per esempio posso inviare dalla mia query di codice C# e nel risultato di questa query otterrò l'informazione che l'operazione SHRINKFILE è finita o no?

+3

Ci si rende conto che questo frammenta il database e interrompe la catena di log, giusto? Questo non è qualcosa che dovresti * mai * automatizzare perché 1) non dovresti * mai * automatizzare la riduzione di un database e 2) La capacità di recupero del tuo database è in pericolo fino al completamento del successivo backup completo. Dovresti farlo sempre manualmente, in via eccezionale, e sorvegliarlo personalmente fino a quando non viene completato. Altrimenti stai invitando una serie di problemi, alcuni dei quali disastrosi. – RBarryYoung

+0

Sono d'accordo con tutto; Questo è il motivo per cui ho bisogno di bloccare tutto cambiando il database mentre riduco ad esempio aggiungere rimuovere le voci di backup, ecc. Il problema è che i nostri requisiti dei clienti hanno bisogno dello spazio inutilizzato sul disco fisso che devo fare. –

+0

Anche per me è sufficiente sapere quando questo processo è finito e non una barra di progresso tutto ciò che devo sapere Quando l'operazione ShrinkFile è terminata nell'istruzione SQL, ad esempio il processo SPID non è più disponibile e posso raggrupparlo da C# –

risposta

16

Il problema con lo stato di misurazione di DBCC SHRINKFILE è che non esiste un modo coerente per il motore di sapere quanto lavoro deve essere fatto per ridurre un file. Per capire questo è sapere come funziona DBCC SHRINKFILE. In sostanza, il processo è:

  • Si dichiara che si desidera ridurre un file a un certo punto (diciamo 5 GB, giù da 10 GB).
  • Il motore inizierà a spostare le pagine dalla fine del file al prossimo punto aperto vicino all'inizio del file.

Shrink File Movement

  • Il motore continua ad andare fino A) si muove abbastanza pagine sotto il vostro punto ha dichiarato che può ridurre la dimensione del file o B) che tutto lo spazio vuoto si trova all'estremità posteriore del file.

Quindi, perché questo significa che SQL Server non sa quanto lavoro deve essere fatto? Perché non sa quanto sia frammentato il tuo spazio vuoto nel file.Se le cose sono abbastanza ben compattate e vicine al fronte del file, il file di restringimento andrà rapidamente. In caso contrario, può richiedere molto tempo. La buona notizia è che una volta spostate le pagine all'interno del file, vengono spostate. Annullare un file di restringimento non annulla/ripristina questo lavoro, quindi se hai un file di restringimento in esecuzione per un po ', poi lo uccidi prima che venga completato, tutto quel movimento di pagina rimane intatto. Il che significa che è possibile riavviare il file di restringimento allo quasi a il punto che si era interrotto (escludendo qualsiasi nuova creazione di pagina all'interno del file).

+0

grazie per la risposta; questo è vero quello che dici ma come posso rilevare che l'operazione di restringimento è in esecuzione !? Posso raggrupparlo fino a quando non è finito. –

+1

Puoi vederlo sotto sp_who2 dove comando è DbccSpaceReclaim o usando [sp_whoisactive] (http://sqlblog.com/files/default.aspx). –

+0

Non riesco a vedere DbCCSpaceReclaim ma riesco a vedere qualcosa di nuovo chiamato AWAITINGCOMMAND questo è venuto nuovo direttamente dopo shrink segnerò lo SPID e controllerò se questo processo di restringimento aspetterò fino a quando questo spid sarà finito Grazie mille segnerò la risposta quando finisco. –

0

Ho risolto il problema in un modo diverso ma questa soluzione non richiede alcun polling o attesa di thread ed è pratica molto.

Questo approccio non riorganizza gli indici delle tabelle ma rimuove solo i file di streaming dal disco rigido e recupera lo spazio libero sul sistema operativo.

Importante conoscere il codice seguente funzionerà sullo stesso thread; Quindi questo non ti farà conoscere il progresso del processo Shrink ma lo eseguirai solo sul thread dell'applicazione.

var db = EFDbContext; 
    try 
    { 
     db.ExecuteSqlCommand(@"USE [master] 

            ALTER DATABASE DatabaseName 
            SET RECOVERY SIMPLE"); 

     db.ExecuteSqlCommand(@"USE [master] 

            EXEC sp_filestream_force_garbage_collection 'DatabaseName'"); 

     db.ExecuteSqlCommand(@"USE [master] 

            EXEC sp_filestream_force_garbage_collection 'DatabaseName'"); 
     } 

    } 
    catch (Exception e) 
    { 
     throw new DatabaseException(e.Message, e); 
    } 
    finally 
    { 
      db.ExecuteSqlCommand(@"USE [master] 
            ALTER DATABASE DatabaseName 
            SET RECOVERY FULL"); 
    }