Как быстро сжать все файлы для всех баз данных?

47

В SQL Server (в данном случае 2008), как я могу быстро сжать все файлы, как журнал, так и данные, для всех баз данных в экземпляре? Я мог бы пройти через SSMS и щелкнуть правой кнопкой мыши по каждой из них и выбрать Задачи -> Сократить, но я ищу что-то быстрее.

Я написал несколько сценариев «Создать базу данных» и забыл, что для значений по умолчанию они имеют раздуваемые размеры, и мне не нужно много места для этих файлов в этом проекте.

Jcolebrand
источник

Ответы:

55

Когда вы делаете «Задачи -> Уменьшить» из графического интерфейса, он фактически выдает DBCC SHRINKDATABASEкоманду за кулисами. Попробуй. Когда появится диалоговое окно, не нажимайте кнопку «ОК». Вместо этого нажмите кнопку «Сценарий». Вы увидите команду в окне запроса. Объедините это с запросом к sys.databases (не указав master и msdb), и вы сможете создать скрипт для сжатия всех баз данных.

Например (взято из комментария Джколебранда):

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;

Скопируйте вывод этого запроса и запустите его, чтобы сжать все ваши файлы.

Ларри Коулман
источник
1
Хорошо, я думаю , что у меня есть то , что я хочу (некрасиво , но делает только то , что мне нужно, чтобы) 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Но полагая , что из дал мне новую проблему. Off, чтобы опубликовать еще один вопрос.
Jcolebrand
Шутки в сторону. Проверьте ответ Сэнди. sp_MSForEachDB (также есть «табличный» sproc) очень полезны
swasheck
3
И вот обязательное напоминание всем, кто читает это: сокращение вашей базы данных опасно.
Ник Чаммас
1
Отфильтровать автономные БД сделало бы это еще лучше. :-)
TiloBunt
1
Согласившись с @TiloBunt, все условие лучше: WHERE d.database_id> 4 AND d.state_desc = 'ONLINE';
Мауро
23

Как насчет одной строки оператора SQL?

Пожалуйста, прочитайте это очень интересное сообщение в блоге перед выполнением следующего SQL-заявления.

EXEC sp_MSForEachDB 'DBCC SHRINKDATABASE (''?'' , 0)'
CoderHawk
источник
6
Одна строка кода не обязательно лучше, если она может работать неправильно. Пожалуйста, прочитайте также эти сообщения, поскольку sp_msforeachdb может пропускать базы данных и не предупреждать вас: sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/… and mssqltips.com/sqlservertip/2201/…
Аарон Бертран
15

DBCC SHRINKDB (и его двоюродный брат SHRINKFILE) работают крайне медленно, потому что в этом коде выполняется много однопоточных операций.

Более быстрый способ сжать файл базы данных:

  • Выделить новую файловую группу в базу данных
  • Сделайте эту файловую группу настолько большой, насколько она должна быть (используйте, sp_spaceusedчтобы определить, насколько большой)
  • Перестройте все индексы для этой новой файловой группы.
  • Удалите старую файловую группу

Поскольку перестройки индекса в основном параллельны, этот метод часто приводит к гораздо более быстрому сокращению базы данных. Конечно, это требует, чтобы у вас было немного дополнительного пространства для новой файловой группы, пока идет процесс. Однако вам нужно только достаточно места в новой файловой группе для хранения самой большой файловой группы в экземпляре (так как вы будете освобождать пространство по мере продвижения).

Этот метод также имеет дополнительное преимущество дефрагментации ваших индексов в процессе.

Томас Кейсер
источник
Вы забыли важную часть. Перестройка индексов больше не будет перемещаться, включая такие вещи, как хранимые процедуры, представления, функции, синонимы, кучи и т. Д. И т. Д.
Джефф Моден
И те не занимают места, о котором вы должны заботиться. Они ДОЛЖНЫ также находиться в файловой группе PRIMARY, вы не можете их переместить (и не должны)
Томас Кейсер,
13

Я немного настроил запрос, чтобы сжать только журнал, как он запрашивается:

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
источник
«быстро сжать все файлы, как журнал, так и данные»
Дезсо
2
Я искал это, и собирался удвоить сообщение, когда я увидел ваш ответ. Не прямой ответ, но ОЧЕНЬ актуально и актуально для моего случая.
Гомибуши
2

Приведенный ниже код, получить список несистемных баз данных, установить базу данных только для чтения и затем сжать файл. Я сохранил этот код в нескольких полях SQL Server, используя задание агента SQL, где пространство всегда является проблемой. Каждую неделю в субботу / субботу он запускается и сокращает все базы данных в течение нескольких часов (в зависимости от размера баз данных).

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

Сократите все файлы журнала, кроме 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'
Эмра Саглам
источник
0

Этот расширяет ответ выше, используя курсор для перебора операторов SQL один за другим. Он не такой короткий, как ответ Эмры, но допускает дополнительную логику в цикле while внутри курсора.

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
источник
0

Мы можем повторить SHRINKDBи SHRINKFILEдля всех баз данных динамически:

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

Вы можете найти подробности в этой статье .

Ануп Кулкарни
источник