Мне нужно сжать базу данных - я просто освободил много места

35

Этот вопрос задается здесь в различных формах, но вопрос сводится к:

Я знаю, что сокращение базы данных рискованно. В этом случае я удалил столько данных и больше никогда не буду их использовать.

  • Как я могу уменьшить свою базу данных? Какие файлы мне сжимать?
  • Какими должны быть мои соображения при этом?
  • Должен ли я сделать что-нибудь после?
  • Что делать, если это большая база данных? Могу ли я уменьшить его в меньших приращениях?
Майк Уолш
источник
2
Я боролся с этим некоторое время назад: dba.stackexchange.com/questions/47310/… Я попытался обобщить свой опыт в своем ответе
Csaba Toth

Ответы:

30

Некоторые начальные предостережения:

  1. Общеизвестно, что худшая практика - когда-либо сокращать производственную базу данных или файл данных (файлы журнала - другая проблема, о которой говорит этот вопрос ). Я советую людям не сжимать свои базы данных в таких сообщениях в блоге, где я говорю о «правильном определении размера» и хорошем планировании. Я там не один ( Пол Рэндал , Брент Озар , просто чтобы предоставить еще пару ссылок). Сжатие файлов данных или индексов фрагментов базы данных является медленным и трудоемким для ваших ресурсов, может привести к утечке в вашей системе и, как правило, является плохой вещью
  2. В этом случае мы все знаем, что риск существует, мы готовы с ним справиться, но мы освободили много места, которое, как мы знаем, больше никогда не понадобится. Так что в этом конкретном случае - сокращение имеет смысл как один из наших вариантов.

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

Есть два основных подхода, которые здесь рассматриваются два:

1.) Сжатие Да, сделать фактическое сжатие - рассмотрите возможность использования DBCC SHRINKFILEвместо DBCC SHRINKDATABASE, у вас есть больше контроля над тем, что сокращается и как. Это наверняка вызовет некоторое снижение производительности - это большая операция, выполняющая много операций ввода-вывода. Вы можете потенциально уйти с повторными стягивается заданного размера , который получает все меньше.

Это пример "A.)" в приведенной выше DBCC SHRINKFILEссылке. В этом примере файл данных сокращается до целевого размера 7 МБ. Этот формат является хорошим способом многократного сжатия, как позволяет ваше окно простоя. Я бы сделал это при тестировании разработки, чтобы увидеть, как выглядит производительность и насколько низко / высоко вы можете пойти с приращением, и определить ожидаемые сроки производства. Это онлайн- операция - вы можете запустить ее с пользователями в системе, которые обращаются к сокращенной базе данных, но при этом почти гарантировано снижение производительности. Поэтому следите и наблюдайте за тем, что вы делаете с сервером, выбирайте окно простоя или период более легкой активности, в идеале.

USE YourDatabase;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO

Всегда помните: - каждый раз, когда вы сжимаете, вы фрагментируете свои индексы и должны выполнять перестройку индекса, если вы собираетесь сокращать порции в течение длительного периода времени. Теперь вы несете эти расходы каждый раз, если не можете сделать все это в одном окне.

2.) Новая база данных - вы можете создать новую базу данных и перенести в нее данные. Вам нужно было бы написать сценарий для пустой базы данных и всех ее ключей, индексов, объектов, процедур, функций и т. Д., А затем перенести в нее данные. Вы можете написать сценарии для этого или использовать такой инструмент, как SQL Data Compare от Red Gate или других поставщиков с аналогичными инструментами. Это больше работы по настройке с вашей стороны, больше разработки и тестирования, и в зависимости от вашей среды может также выбить ваше окно простоя, но вариант, который нужно учитывать.

Когда я буду вынужден сжать базу данных Если бы это было мое окружение, я хотел бы посмотреть , чтобы оставить изрядное / здоровенное количество белого пространства в файл данных , потому что мне нравится быть на диск боров и как подготовиться к будущему / непредвиденному росту. Поэтому я был бы согласен вернуть пространство обратно, если бы мы просто удалили большую часть пространства, но я бы никогда не поверил тем, кто говорит «но оно никогда не вырастет снова», и все равно оставил бы некоторое пространство. Маршрут, по которому я бы, вероятно, пошел ( вздох) - это сжатый подход, если у меня были меньшие окна простоя и я не хотел брать на себя сложность создания пустой БД и переноса данных в нее. Поэтому я постепенно уменьшал его (в зависимости от того, сколько раз я думал, что мне нужно было основываться на моем тестировании в dev и желаемого размера. Постепенно выбирая меньший размер файла), а затем перестраивал индексы ... И тогда я ' никогда не говори никому, что я сжал свою базу данных ;-)

Майк Уолш
источник
1
Я бы добавил особый случай, когда вы удалили много данных из кучи (особенно из середины кучи), вы не сможете вернуть это пространство, пока не добавите в него кластерный индекс (надеюсь, навсегда), а затем отбросить кластерный индекс после (превратив его обратно в кучу). Конечно, если куча усекается регулярно, то проблем нет. Но все же стоит упомянуть.
Джонатан
Может кто-нибудь объяснить значение NOTRUNCATE AND TRUNCATEONLY, по-видимому, последнее не переставляет страницы и, следовательно, не вызывает фрагментации индекса?
Дэвид Гарсия
4
  1. Как я могу уменьшить свою базу данных? Какие файлы мне сжимать? : Вы можете сжать файлы по отдельности с помощью указанной DBCC SHRINKFILEвами команды. Это зависит от вашего сервера, сколько файлов состоит из вашей базы данных. Простая база данных имеет один файл базы данных и один файл журнала транзакций.
  2. Какими должны быть мои соображения при этом?: сокращение влияет на фрагментацию вашего индекса, см. 3-й пункт. Также обратите внимание, что вы не хотите уменьшать размер файла базы данных до минимально возможного размера, потому что в реальной среде он все равно будет расти. Поэтому я бы настроил размер (в вашем примере вы дали 7 мегабайт) таким образом, чтобы в файле базы данных оставалось 10% -20% свободного места, потому что оно в любом случае будет заполнено в рабочей среде, и вы можете таким образом сохраните несколько циклов автоматического роста. Поэтому фактическое число требует тщательного расчета. Также обратите внимание, что выполненное вами «освобождение большого пространства» приведет к увеличению размера файла журнала транзакций даже больше, чем пространство, которое вы получили в файле БД. Кроме того, фактический выигрыш в космосе будет меньше, чем вы ожидаете математически! Допустим, вы математически освободили 12 концертов,
  3. Должен ли я сделать что-нибудь после? Как я упоминал ранее, вы хотите переиндексировать те индексы, фрагментация которых была искажена в результате изменений SHRINK. Я недостаточно экспериментировал, если вам нужно сделать что-то особенное в статистике запросов.
  4. Что делать, если это большая база данных? Могу ли я уменьшить его в меньших приращениях? Операция SHRINK может быть прервана в любое время, и вы можете продолжить позже. Я бы посоветовал выполнить это в автономной базе данных, если это возможно. Прервав и продолжив, он все равно получит такой же размер усадки. Теоретически вы можете сжиматься меньшими приращениями, указав менее жесткий целевой размер вместо 7 мегабайт, но я бы сказал, что если вы выполняете его в производстве, то просто дайте ему один шаг. Как видите, есть проблемы с фрагментацией индекса и возможным ростом журнала транзакций. Так что я бы прошел через это только один раз.

Мы все знаем, что не рекомендуется делать SHRINK регулярно в любом случае. Я стараюсь исключить все предупреждения и отказы от ответственности, которые вы, вероятно, знаете в любом случае. Сделайте резервную копию, и не делайте этого дома, если это возможно :)

Бонус: в среде репликации, если вы выполните это в базе данных издателя, это не приведет к сокращению баз данных подписчиков (что может иметь проблему с размером, поскольку они являются выпусками Express).

Наконец, мой скрипт переиндексации:

USE YourDBName

DECLARE @TbName VARCHAR(255)
DECLARE @FullTbName VARCHAR(255)
DECLARE @IxName VARCHAR(255)
DECLARE myCursor CURSOR FOR
    SELECT OBJECT_NAME(dmi.object_id) AS TableName,i.name AS IndexName
    FROM sys.dm_db_index_physical_stats(14, NULL, NULL, NULL , 'LIMITED') dmi
    JOIN  sys.indexes i on dmi.object_id = i.object_id and dmi.index_id = i.index_id
    WHERE avg_fragmentation_in_percent > 30
    ORDER BY avg_fragmentation_in_percent
OPEN myCursor
FETCH NEXT FROM myCursor INTO @TbName, @ixName
WHILE @@FETCH_STATUS = 0
BEGIN
    IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'dba' AND TABLE_NAME = @TbName)
BEGIN
        SET @FullTbName = 'dba.' + @TbName
        IF (@ixName IS NULL)
        BEGIN
            PRINT 'Reindexing Table ' + @FullTbName
            DBCC DBREINDEX(@FullTbName, '', 0)
        END
        ELSE
        BEGIN
             PRINT 'Reindexing Table ' + @FullTbName + ', Index ' + @IxName
             DBCC DBREINDEX(@FullTbName, @IxName, 0)
        END
    END
    FETCH NEXT FROM myCursor INTO @TbName, @ixName
END
CLOSE myCursor
DEALLOCATE myCursor

Единственная переменная в этом - это 14, которую можно получить с помощью команды select DB_ID('YourDBName'), и сценарий предполагает, что вас интересуют только таблицы в схеме dba. *.

Чаба Тот
источник
2
Заметьте, что перестройка индекса помечена как устаревшая в SQL 2005 DBREINDEX. Вместо огромного скрипта с курсорами вы можете просто использовать: EXEC sp_MSForeachtable @ Command1 = "ALTER INDEX ALL ON? REBUILD" Надеюсь, это кому-нибудь поможет.
ПОЦЕЛУЙ
2

Вы слышали все предупреждения о сокращении баз данных, и все они верны. Он будет фрагментировать ваши индексы и, в целом, испортит вашу базу данных и не должен выполняться в производственной системе.

Но я обычно делаю это еженедельно, когда восстанавливаю резервную копию на моей рабочей станции из-за свободного места на моем SSD-диске. Имейте в виду, я не писал этот сценарий, но нашел его несколько лет назад. В других базах данных [250 ГБ] я создал пакет служб SSIS, который перенесет нужные мне таблицы, а затем заново создаст индексы для этого очень свежего ощущения индекса.

DECLARE @DBFileName SYSNAME

DECLARE @TargetFreeMB INT

DECLARE @ShrinkIncrementMB INT

SET @DBFileName = 'Set Name of Database file to shrink'

-- Set Desired file free space in MB after shrink

SET @TargetFreeMB = 500
-- Set Increment to shrink file by in MB
SET @ShrinkIncrementMB = 100

SELECT [FileSizeMB] = convert(NUMERIC(10, 2),
round(a.size / 128., 2)),

[UsedSpaceMB] = convert(NUMERIC(10, 2),

round(fileproperty(a.NAME, 'SpaceUsed') / 128., 2)),

[UnusedSpaceMB] = convert(NUMERIC(10, 2),

round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2)),

[DBFileName] = a.NAME

FROM sysfiles a

DECLARE @sql VARCHAR(8000)
DECLARE @SizeMB INT
DECLARE @UsedMB INT

SELECT @SizeMB = size / 128.
FROM sysfiles
WHERE NAME = @DBFileName

SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

SELECT [StartFileSize] = @SizeMB
    ,[StartUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

WHILE @SizeMB > @UsedMB + @TargetFreeMB + @ShrinkIncrementMB

BEGIN
    SET @sql = 'dbcc shrinkfile ( ' + @DBFileName + ', ' + convert(VARCHAR(20), @SizeMB - @ShrinkIncrementMB) + ' ) '

    PRINT 'Start ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    EXEC (@sql)

    PRINT 'Done ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    SELECT @SizeMB = size / 128.
    FROM sysfiles
    WHERE NAME = @DBFileName

    SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

    SELECT [FileSize] = @SizeMB
        ,[UsedSpace] = @UsedMB
        ,[DBFileName] = @DBFileName
END

SELECT [EndFileSize] = @SizeMB
    ,[EndUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

SELECT [FileSizeMB] = convert(NUMERIC(10, 2), round(a.size / 128., 2))

    ,[UsedSpaceMB] = convert(NUMERIC(10, 2), round(fileproperty a.NAME, 'SpaceUsed') / 128., 2))

,[UnusedSpaceMB] = convert(NUMERIC(10, 2), round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2))

,[DBFileName] = a.NAME

FROM sysfiles a
user1207758
источник
1

Приведенная ниже цитата взята непосредственно из Microsoft (относится к версиям 2008-2016) и дает указания относительно того, следует ли использовать DBCC SHRINKFILEкоманду, когда и когда .

https://msdn.microsoft.com/en-us/library/ms189493.aspx

Лучшие практики

Рассмотрите следующую информацию, когда вы планируете сжать файл:

  • Операция сжатия наиболее эффективна после операции, которая создает много неиспользуемого пространства, такого как усеченная таблица или операция удаления таблицы.
  • Большинству баз данных требуется некоторое свободное пространство, чтобы быть доступным для регулярных повседневных операций. Если вы несколько раз сжимаете базу данных и замечаете, что размер базы данных снова увеличивается, это означает, что сокращенное пространство требуется для обычных операций. В этих случаях многократное сжатие базы данных является бесполезной операцией.
  • Операция сжатия не сохраняет состояние фрагментации индексов в базе данных и в целом увеличивает степень фрагментации. Это еще одна причина не многократно сокращать базу данных.
  • Сокращайте несколько файлов в одной базе данных последовательно, а не одновременно. Конфликт в системных таблицах может вызвать задержки из-за блокировки.
g2server
источник