Wie kann ich alle Dateien für alle Datenbanken schnell verkleinern?

47

Wie kann ich in SQL Server (in diesem Fall 2008) schnell alle Dateien (Protokoll und Daten) für alle Datenbanken einer Instanz verkleinern? Ich könnte durch SSMS gehen und mit der rechten Maustaste auf jede klicken und Aufgaben -> Verkleinern wählen, aber ich suche etwas schnelleres.

Ich habe einige "Datenbank erstellen" -Skripte geschrieben und vergessen, dass sie aufgrund von Standardeinstellungen eine überhöhte Größe haben und nicht so viel Platz für diese Dateien in diesem Projekt benötigen.

jcolebrand
quelle

Antworten:

55

Wenn Sie in der GUI "Aufgaben -> Verkleinern" ausführen, wird tatsächlich ein DBCC SHRINKDATABASEBefehl hinter den Kulissen ausgegeben. Versuch es. Wenn das Dialogfeld angezeigt wird, klicken Sie nicht auf die Schaltfläche "OK". Klicken Sie stattdessen auf die Schaltfläche "Skript". Der Befehl wird in einem Abfragefenster angezeigt. Kombinieren Sie dies mit einer Abfrage in sys.databases (lassen Sie master und msdb weg), und Sie können ein Skript erstellen, um alle Datenbanken zu verkleinern.

Zum Beispiel (aus jcolebrands Kommentar entnommen):

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;

Kopieren Sie die Ausgabe dieser Abfrage und führen Sie sie aus, um alle Ihre Dateien zu verkleinern.

Larry Coleman
quelle
1
Ok, ich glaube, ich habe, was ich will (hässlich, aber tut genau das, wozu ich es brauche). 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 > 4Aber das herauszufinden, gab mir ein neues Problem. Aus, um eine weitere Frage zu stellen.
Jcolebrand
Ernsthaft. Schauen Sie sich die Antwort von @ Sandy an. die sp_MSForEachDB (es gibt auch einen "table" sproc) sind extrem hilfreich
swasheck
3
Und hier ist die obligatorische Erinnerung an alle, die dies lesen: Das Verkleinern Ihrer Datenbank ist gefährlich.
Nick Chammas
1
Offline-DB herausfiltern würde es noch besser machen. :-)
TiloBunt
1
In Übereinstimmung mit @ TiloBunt ist die gesamte Bedingung besser als WHERE d.database_id> 4 AND d.state_desc = 'ONLINE';
Mauro
23

Wie wäre es mit einer einzelnen Zeile der SQL-Anweisung?

Bitte lesen Sie diesen sehr interessanten Blog-Beitrag, bevor Sie die folgende SQL-Anweisung ausführen.

EXEC sp_MSForEachDB 'DBCC SHRINKDATABASE (''?'' , 0)'
CoderHawk
quelle
6
Eine einzelne Codezeile ist nicht unbedingt besser, wenn sie möglicherweise nicht richtig funktioniert. Bitte lesen Sie auch diese Beiträge, da sp_msforeachdb Datenbanken überspringen und Sie nicht warnen kann: sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/… und mssqltips.com/sqlservertip/2201/…
Aaron Bertrand
15

DBCC SHRINKDB (und sein Cousin SHRINKFILE) sind extrem langsam, da in diesem Code viel Single-Thread-Ausführung stattfindet.

Eine viel schnellere Methode zum Verkleinern einer Datenbankdatei ist die folgende:

  • Ordnen Sie der Datenbank eine neue Dateigruppe zu
  • Machen Sie diese Dateigruppe so groß wie nötig (verwenden Sie diese Option, um sp_spaceusedzu bestimmen, wie groß sie sein soll).
  • Erstellen Sie alle Indizes für diese neue Dateigruppe neu
  • Löschen Sie die alte Dateigruppe

Da Indexwiederherstellungen weitgehend parallel sind, führt diese Technik häufig zu einer viel schnelleren Verkleinerung der Datenbank. Natürlich müssen Sie ein wenig zusätzlichen Speicherplatz für die neue Dateigruppe haben, während der Prozess abläuft. Sie benötigen jedoch nur genügend Speicherplatz in der neuen Dateigruppe, um die größte Dateigruppe in der Instanz aufzunehmen (da Sie währenddessen Speicherplatz zurückfordern).

Diese Technik hat auch den zusätzlichen Vorteil, dass Ihre Indizes dabei defragmentiert werden.

Thomas Kejser
quelle
Sie haben einen wichtigen Teil vergessen. Durch das Neuerstellen von Indizes werden keine anderen
Jeff Moden,
Und diese benötigen keinen Platz, den Sie interessieren sollten. Sie MÜSSEN sich auch in der PRIMARY-Dateigruppe aufhalten, Sie können sie nicht wirklich verschieben (und Sie sollten es auch nicht)
Thomas Kejser,
13

Ich habe ein wenig die Abfrage angepasst, um nur das LOG zu verkleinern, wie es angefordert wird:

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'
Frankachela
quelle
"
Verkleinern Sie
2
Ich habe danach gesucht und wollte gleich doppelt posten, als ich Ihre Antwort sah. Keine direkte Antwort, aber SEHR relevant und genau richtig für meinen Fall.
Gomibushi
2

Im folgenden Code wird eine Liste der Nicht-Systemdatenbanken angezeigt. Legen Sie fest, dass die Datenbank schreibgeschützt ist, und verkleinern Sie die Datei. Ich habe diesen Code mithilfe von SQL Agent Job in einigen SQL Server-Boxen gespeichert, in denen der Speicherplatz immer ein Problem darstellt. Wöchentlich in der Nacht von Samstag auf Sonntag werden alle Datenbanken innerhalb weniger Stunden ausgeführt und verkleinert (abhängig von der Größe der Datenbanken).

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
Muhammad Sharjeel Ahsan
quelle
0

Verkleinern Sie alle Protokolldateien außer master, model, 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'
Emrah Saglam
quelle
0

Diese erweitert die Antwort oben und verwendet einen Cursor, um die SQL-Anweisungen nacheinander zu durchlaufen. Es ist nicht so kurz wie Emrahs Antwort, aber es erlaubt zusätzliche Logik innerhalb der while-Schleife innerhalb des Cursors.

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
Alistair
quelle
0

Wir können SHRINKDBund SHRINKFILEfür alle Datenbanken dynamisch wiederholen :

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

Details finden Sie in diesem Artikel .

Anup Kulkarni
quelle