Come posso ridurre rapidamente tutti i file per tutti i database?


47

In SQL Server (2008 in questo caso) come posso ridurre rapidamente tutti i file, sia di registro che di dati, per tutti i database su un'istanza? Potrei passare attraverso SSMS e fare clic con il tasto destro su ciascuno e scegliere Attività -> Riduci, ma sto cercando qualcosa di più veloce.

Ho scritto alcuni script "Crea database" e ho dimenticato che avevano dimensioni in mongolfiera per impostazione predefinita, e non ho bisogno di molto spazio riservato per questi file in questo progetto.

Risposte:


55

Quando esegui "Attività -> Riduci" dalla GUI, in realtà emette un DBCC SHRINKDATABASEcomando dietro le quinte. Provalo. Quando viene visualizzata la finestra di dialogo, non fare clic sul pulsante "OK". Invece, fai clic sul pulsante "Script". Vedrai il comando in una finestra di query. Combinalo con una query su sys.database (tralascia master e msdb) e puoi creare uno script per ridurre tutti i database.

Ad esempio (tratto dal commento di jcolebrand):

SELECT 
      'USE [' + d.name + N']' + CHAR(13) + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' + mf.name + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 
FROM 
         sys.master_files mf 
    JOIN sys.databases d 
        ON mf.database_id = d.database_id 
WHERE d.database_id > 4;

Copia l'output di quella query ed eseguilo per ridurre tutti i tuoi file.


1
Ok, penso di avere quello che voglio (brutto ma fa proprio quello di cui ho bisogno) SELECT 'USE [' + d.name + N']' + CHAR(13) + CHAR(10) + 'DBCC SHRINKFILE (N''' + mf.name + N''' , 0, TRUNCATEONLY)' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) FROM sys.master_files mf JOIN sys.databases d ON mf.database_id = d.database_id WHERE d.database_id > 4Ma capire che mi ha dato un nuovo problema. Off per pubblicare un'altra domanda.
jcolebrand

Sul serio. Dai un'occhiata alla risposta di @ Sandy. gli sp_MSForEachDB (c'è anche uno sproc "table") sono estremamente utili
swasheck

3
Ed ecco il promemoria obbligatorio per tutti coloro che stanno leggendo questo: ridurre il database è pericoloso.
Nick Chammas,

1
filtrare il DB offline lo renderebbe ancora migliore. :-)
TiloBunt,

1
Concordato con @TiloBunt, l'intera condizione è migliore di WHERE d.database_id> 4 AND d.state_desc = 'ONLINE';
Mauro,

23

Che ne dici di una singola riga di istruzione sql?

Si prega di leggere questo post sul blog molto interessante prima di eseguire la seguente istruzione sql.

EXEC sp_MSForEachDB 'DBCC SHRINKDATABASE (''?'' , 0)'

6
Una singola riga di codice non è necessariamente migliore se potrebbe non funzionare correttamente. Ti preghiamo di leggere anche questi post, poiché sp_msforeachdb può saltare i database e non avvisarti: sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/… e mssqltips.com/sqlservertip/2201/…
Aaron Bertrand

15

DBCC SHRINKDB (e suo cugino SHRINKFILE) sono estremamente lenti, poiché in quel codice è in corso molta esecuzione a thread singolo.

Un modo molto più veloce per ridurre un file di database è questo:

  • Allocare un nuovo filegroup al database
  • Rendi questo filegroup grande come deve essere (usa sp_spaceusedper determinare quanto è grande)
  • Ricostruisci tutti gli indici in questo nuovo filegroup
  • Rilascia il vecchio filegroup

Poiché le ricostruzioni degli indici sono enormemente parallele, questa tecnica si traduce spesso in una riduzione molto più rapida del database. Ovviamente, ti richiede di avere un po 'di spazio extra per il nuovo filegroup mentre il processo è in corso. Tuttavia, è necessario solo uno spazio sufficiente nel nuovo filegroup per contenere il filegroup più grande nell'istanza (poiché verrà recuperato lo spazio man mano che si procede).

Questa tecnica ha anche l'ulteriore vantaggio di deframmentare gli indici nel processo.


Hai dimenticato una parte importante. La ricostruzione di indici non sposterà nient'altro incluso cose come procedure memorizzate, viste, funzioni, sinonimi, cumuli, ecc. Ecc.
Jeff Moden

E quelli non occupano spazio di cui dovresti preoccuparti. Devono risiedere anche nel filegroup PRIMARY, non puoi davvero spostarli (e nemmeno tu dovresti)
Thomas Kejser il

13

Ho sintonizzato un po 'la query per ridurre solo il LOG come richiesto:

set nocount on  
SELECT 
      'USE [' + d.name + N']' + CHAR(13) + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' + mf.name + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) 
FROM 
         sys.master_files mf 
    JOIN sys.databases d 
        ON mf.database_id = d.database_id 
WHERE d.database_id > 4 and mf.type_desc = 'LOG'


2
Lo stavo cercando e stavo per raddoppiare il post quando ho visto la tua risposta. Risposta non diretta, ma MOLTO pertinente e precisa per il mio caso.
Gomibushi,

2

Il codice seguente, ottiene un elenco di database non di sistema, imposta il database in sola lettura e quindi riduce il file. Ho conservato questo codice in alcune caselle di SQL Server utilizzando SQL Agent Job, dove lo spazio è sempre un problema. Ogni sabato / domenica notte inizia a funzionare e riduce tutti i database in poche ore (a seconda della dimensione dei database).

declare @db varchar(255)
declare c cursor for
select name from sys.databases where is_read_only=0 and state=0
  and name not in ('master','model','tempdb','msdb')
open c
fetch c into @db
while @@fetch_status=0
begin
  exec SP_dboption @db,'trunc. log on chkpt.','true' 
  DBCC shrinkdatabase (@db)
  fetch next from c into @db
end
close c
deallocate c

0

Riduci tutti i file di registro tranne master, modello, msdb:

EXEC sp_MSforeachdb '
DECLARE @sqlcommand nvarchar (500)
IF ''?'' NOT IN (''master'', ''model'', ''msdb'')
BEGIN
USE [?]
SELECT @sqlcommand = ''DBCC SHRINKFILE (N'''''' + 
name
FROM [sys].[database_files]
WHERE type_desc = ''LOG''
SELECT @sqlcommand = @sqlcommand + '''''' , 0)''
EXEC sp_executesql @sqlcommand
END'

0

Questo estende la risposta sopra, usando un cursore per scorrere una alla volta le istruzioni SQL. Non è breve come la risposta di Emrah, ma consente una logica aggiuntiva all'interno del ciclo while all'interno del cursore ..

SELECT 
    'USE [' 
    + databases.name + N']' 
    + CHAR(13) 
    + CHAR(10) 
    + 'DBCC SHRINKFILE (N''' 
    + masterFiles.name 
    + N''' , 0, TRUNCATEONLY)' 
    + CHAR(13) 
    + CHAR(10) 
    + CHAR(13) 
    + CHAR(10)                                                                  AS sqlCommand
INTO
    #shrinkCommands
FROM 
    [sys].[master_files] masterFiles 
    INNER JOIN [sys].[databases] databases ON masterFiles.database_id = databases.database_id 
WHERE 
    databases.database_id > 4; -- Exclude system DBs


DECLARE iterationCursor CURSOR

FOR
    SELECT 
        sqlCommand 
    FROM 
        #shrinkCommands

OPEN iterationCursor

DECLARE @sqlStatement varchar(max)

FETCH NEXT FROM iterationCursor INTO @sqlStatement

WHILE (@@FETCH_STATUS = 0)
BEGIN
    EXEC(@sqlStatement)
    FETCH NEXT FROM iterationCursor INTO @sqlStatement
END

-- Clean up
CLOSE iterationCursor
DEALLOCATE iterationCursor
DROP TABLE #shrinkCommands

0

Possiamo ripetere dinamicamente SHRINKDBe SHRINKFILEper tutti i database:

while @DBID<=@MaxDBID
begin
  -- Used Dynamic SQL for all databases.
  Set @SQL ='Use '+@DBName+ ' '+Char(10)
  Set @SQL += 'DBCC SHRINKFILE('+@Filename+',5)' +Char(10)
  Set @SQL += 'DBCC SHRINKDATABASE('+@DBName+')'+Char(10)

  --#6 Increment DBid for looping over all databases
  Set @DBID = @DBID+1
  Select @DBName = DBName, @Filename=DBFileName from #DBNames where [dbid] = @DBID and type_Desc = 'LOG'
  Print (@SQL)
  Exec (@SQL)
end

Puoi trovare i dettagli in questo articolo .

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.