Jak szybko zmniejszyć wszystkie pliki dla wszystkich baz danych?

47

Jak w programie SQL Server (w tym przypadku w 2008 r.) Mogę szybko zmniejszyć wszystkie pliki, zarówno dziennik, jak i dane, dla wszystkich baz danych w instancji? Mógłbym przejść przez SSMS i kliknąć każdy z nich prawym przyciskiem myszy i wybrać Zadania -> Zmniejsz, ale szukam czegoś szybszego.

Skryptowałem niektóre skrypty „Utwórz bazę danych” i zapomniałem, że miały one domyślne ustawienia rozmiarów w dymkach i nie potrzebuję tyle miejsca zarezerwowanego dla tych plików w tym projekcie.

jcolebrand
źródło

Odpowiedzi:

55

Kiedy wykonujesz „Zadania -> Zmniejsz” z GUI, faktycznie wydaje DBCC SHRINKDATABASEpolecenie za sceną. Spróbuj. Kiedy pojawi się okno dialogowe, nie klikaj przycisku „OK”. Zamiast tego kliknij przycisk „Skrypt”. Zobaczysz polecenie w oknie zapytania. Połącz to z zapytaniem w sys.databases (pomiń master i msdb), a możesz stworzyć skrypt, aby zmniejszyć wszystkie bazy danych.

Na przykład (wzięty z komentarza 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;

Skopiuj dane wyjściowe tego zapytania i uruchom je, aby zmniejszyć wszystkie pliki.

Larry Coleman
źródło
1
Ok, myślę, że mam co chcę (brzydki, ale nie tylko to, co mi potrzebne do) 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 > 4Ale zastanawianie że spośród dał mi nowy problem. Off, aby opublikować kolejne pytanie.
jcolebrand
Poważnie. Sprawdź odpowiedź @ Sandy. sp_MSForEachDB (istnieje również sproc „tabeli”) są niezwykle pomocne
swasheck
3
A oto obowiązkowe przypomnienie dla wszystkich, którzy to czytają: Zmniejszenie bazy danych jest niebezpieczne.
Nick Chammas
1
odfiltrowanie Offline DB uczyniłoby to jeszcze lepszym. :-)
TiloBunt
1
Uzgodniony z @TiloBunt, cały warunek jest lepszy, ponieważ GDZIE d.database_id> 4 AND d.state_desc = 'ONLINE';
Mauro
23

Co powiesz na jedną linię instrukcji SQL?

Przeczytaj ten bardzo interesujący post na blogu przed wykonaniem następującego polecenia sql.

EXEC sp_MSForEachDB 'DBCC SHRINKDATABASE (''?'' , 0)'
CoderHawk
źródło
6
Pojedyncza linia kodu niekoniecznie jest lepsza, jeśli może nie działać poprawnie. Przeczytaj również te posty, ponieważ sp_msforeachdb może pomijać bazy danych i nie ostrzegać: sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/… oraz mssqltips.com/sqlservertip/2201/...
Aaron Bertrand
15

DBCC SHRINKDB (i jego kuzyn SHRINKFILE) są bardzo powolne, ponieważ w tym kodzie dzieje się wiele pojedynczych wątków.

Znacznie szybszy sposób zmniejszenia pliku bazy danych jest następujący:

  • Przydziel nową grupa plików do bazy danych
  • Ustaw tę grupa plików tak dużą, jak powinna być (użyj, sp_spaceusedaby określić, jak duża)
  • Odbuduj wszystkie indeksy do tej nowej grupy plików
  • Upuść starą grupę plików

Ponieważ przebudowy indeksu są masowo równoległe, technika ta często powoduje znacznie szybsze zmniejszanie bazy danych. Oczywiście wymaga to trochę dodatkowej przestrzeni dla nowej grupy plików podczas trwania procesu. Jednak potrzebna jest tylko wystarczająca ilość miejsca w nowej grupie plików, aby pomieścić największą grupę plików w instancji (ponieważ będziesz odzyskiwać miejsce podczas pracy).

Ta technika ma również dodatkową zaletę defragmentacji indeksów w tym procesie.

Thomas Kejser
źródło
Zapomniałeś ważnej części. Przebudowywanie indeksów nie przeniesie niczego innego, w tym takich procedur, jak procedury składowane, widoki, funkcje, synonimy, stosy itp.
Jeff Moden
A te nie zajmują miejsca, o które powinieneś dbać. MUSZĄ także przebywać w grupie plików PODSTAWOWEJ, tak naprawdę nie można ich przenieść (i nie należy również)
Thomas Kejser
13

Zoptymalizowałem trochę zapytanie, aby zmniejszyć tylko LOG, zgodnie z żądaniem:

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
źródło
„szybko zmniejsz wszystkie pliki, zarówno dziennik, jak i dane”
dezso
2
Szukałem tego i miałem zamiar podwoić wpis, kiedy zobaczyłem twoją odpowiedź. Nie bezpośrednia odpowiedź, ale BARDZO trafna i trafna w mojej sprawie.
Gomibushi,
2

Poniższy kod, pobierz listę niesystemowych baz danych, ustaw bazę danych tylko do odczytu, a następnie zmniejsz plik. Trzymałem ten kod w kilku polach programu SQL Server za pomocą SQL Agent Job, gdzie zawsze jest miejsce. W soboty i niedziele co tydzień zaczyna się uruchamiać i zmniejszać wszystkie bazy danych w ciągu kilku godzin (w zależności od wielkości baz danych).

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
źródło
0

Zmniejsz wszystkie pliki dziennika oprócz głównego, modelu, 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
źródło
0

Ten rozszerza powyższą odpowiedź, używając kursora do iteracji kolejno instrukcji SQL. Nie jest tak krótki jak odpowiedź Emrah'a, ale pozwala na dodatkową logikę w pętli while w obrębie kursora.

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
źródło
0

Możemy dynamicznie powtarzać SHRINKDBi SHRINKFILEdla wszystkich baz danych:

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

Szczegóły znajdziesz w tym artykule .

Anup Kulkarni
źródło