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


35

Це запитання задається тут у різних формах, але це питання зводиться до:

Я знаю, скорочення бази даних ризиковано. У цьому випадку я видалив стільки даних, і більше ніколи не буду їх використовувати.

  • Як я можу скоротити свою базу даних? Які файли я скорочую?
  • Якими повинні бути мої міркування при цьому?
  • Чи варто робити щось після?
  • Що робити, якщо це велика база даних? Чи можу я скоротити його меншими кроками?

2
Я боровся з цим деякий час тому: dba.stackexchange.com/questions/47310/… Я спробував узагальнити свій досвід у своїй відповіді
Csaba Toth

Відповіді:


30

Деякі початкові застереження:

  1. Як правило, найгірша практика коли-небудь скорочувати виробничу базу даних або файл даних (файли журналів - це ще одна проблема, про яку йдеться у цьому питанні ). Я раджу людям не зменшувати свої бази даних у публікаціях блогу, як це, де я говорю про "правильний розмір" та гарне планування. Я не один там ( Пол Рандал , Брент Озар , лише щоб надати ще пару посилань). Зменшення індексів файлу даних або фрагментів бази даних є повільним та трудомістким на ваших ресурсах, може спричинити злиття вашої системи і, як правило, погано робити.
  2. У цьому випадку ми всі знаємо, що існує ризик, ми готові з цим боротися, але ми звільнили багато місця, яке ми знаємо, що більше ніколи не будемо потребувати. Отже, у цьому конкретному випадку - зменшення має багато сенсу як один із наших варіантів.

Якщо ви читали про занепокоєння та ризики, і вам все-таки потрібно зробити це зменшення, оскільки ви звільнили значну кількість місця, сподіваємось, решта цієї відповіді допоможе вам допомогти. Але врахуйте ризики.

Тут розглядаються два основні підходи:

1.) Термозбіжний Так, зробіть фактичну усадку - Розгляньте можливість використання DBCC SHRINKFILEзамість DBCC SHRINKDATABASE, ви маєте більше контролю над тим, що отримує усадку і як. Це точно призведе до деякої погіршення продуктивності - це велика операція, яка робить багато IO. Ви можете потенційно піти від повторних скорочень до цільового розміру, який стає прогресивно меншим.

Це приклад "А.)" у наведеному вище DBCC SHRINKFILEпосиланні. У цьому прикладі файл даних скорочується до цільового розміру 7 Мб. Цей формат - хороший спосіб скорочуватися неодноразово, оскільки дозволяє вікно простою. Я б зробив це при тестуванні на розробку, щоб побачити, як виглядає продуктивність і наскільки низький / високий ви можете збільшити приріст і визначити очікувані терміни виробництва. Це операція в Інтернеті - ви можете запустити її з користувачами в системі, що отримує доступ до скороченої бази даних, але деградація роботи буде майже гарантована. Тому стежте і спостерігайте за тим, що ви робите з сервером, вибирайте вікно простою або період легшої активності, в ідеалі.

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

Завжди пам’ятайте: - кожен раз, коли ви стискаєте, ви фрагментуєте ваші індекси, і вам слід робити перебудову індексу, якщо ви збираєтеся скорочувати шматки протягом тривалого періоду часу. Тепер ви несете цю ціну щоразу, якщо не зможете зробити це все в одному вікні.

2.) Нова база даних - Ви можете створити нову базу даних та перемістити дані до неї. Вам доведеться скриптувати порожню базу даних і всі її ключі, індекси, об'єкти, програми, функції тощо, а потім перемістити дані до неї. Ви можете написати сценарії для цього або скористатися таким інструментом, як SQL Data Порівняння від Red Gate або інших постачальників з подібними інструментами. Це більше налаштування на вашій стороні, більше розробки та тестування, і залежно від вашого оточення також може підірвати ваше вікно простою, але також можливість розглянути.

Коли я змушений скорочувати базу даних, якби це моє середовище, я б хотів залишити у файлі даних неабиякий / здоровенний пробіл, тому що мені подобається бути дисковим свиням і люблю бути готовим до майбутнього / несподіваного зростання. Так що я б добре давання простір назад , якщо ми просто видалили більшу частину простору, але я б ніколи не довіряти тим , кажучи «але він ніколи не буде знову рости» і залишити деякий порожній простір. Маршрут, напевно, я б пішов ( зітхаючи) - це зменшення підходу, якщо б у мене були менші вільні простої та не хотілося виникати складності створення порожнього БД та міграції даних до нього. Тож я б зменшував її поступово (залежно від того, скільки разів я вважав, що потрібно на основі мого тестування на розробці та потрібного розміру. Поступово вибираючи менший розмір файлу), а потім відновлюйте індекси .. І тоді я ' я ніколи не скажу нікому, що я скоротив свою базу даних ;-)


1
Я додам особливий випадок, що якщо ви видалите багато даних із купи (особливо з середини купи), ви не зможете повернути цей простір, доки не додасте до нього кластерний індекс (сподіваємось назавжди), а потім скиньте кластерний індекс після (перетворення його назад у купу). Звичайно, якщо купа регулярно обрізається, то жодних проблем. Але все ж варто згадати.
Джонатан Фейт

Чи може хтось пояснити наслідки NOTRUNCATE AND TRUNCATEONLY, мабуть, остання не переставляє сторінки і тому не викликає фрагментації індексу?
Девід Гарсія

4
  1. Як я можу скоротити свою базу даних? Які файли я скорочую? : Ви можете стискати файли окремо за DBCC SHRINKFILEвказаною вами командою. Від вашого сервера залежить, скільки файлів складається з вашої бази даних. Проста база даних має один файл бази даних та один файл журналу транзакцій.
  2. Якими повинні бути мої міркування при цьому?: зменшення впливає на фрагментацію вашого індексу, див. 3-ю точку. Також зауважте, що ви не хочете зменшувати файл бази даних до мінімально можливого розміру, оскільки в реальному середовищі він все одно зросте. Тож я налаштував би розмір (у вашому прикладі ви дали 7 мегабайт) таким чином, щоб ви залишили 10% -20% вільного місця у файлі бази даних, оскільки він все одно заповниться у виробничому середовищі, і ви можете таким чином збережіть кілька циклів автоматичного зростання. Тож фактична кількість потребує ретельного підрахунку. Також зауважте, що виконаний вами "великий пробіл простору" підірвав би файл журналу транзакцій навіть більше, ніж простір, який ви отримали у файлі DB. Крім того, фактичний виграш місця, який ви можете зазнати, буде меншим, ніж ви математично очікуєте! Скажімо, ви математично звільнили 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
Для відновлення індексу зауважте, що DBREINDEX був застарілий у SQL 2005. Замість величезного сценарію з курсорами ви можете просто використовувати: EXEC sp_MSForeachtable @ Command1 = "ALTER INDEX ALL ON? REBUILD" Сподіваюся, що це комусь допоможе.
KISS

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

1

Ця цитата нижче безпосередньо від Microsoft (стосується версій 2008-2016 рр.) Та дає вказівки щодо того, чи / коли та як слід використовувати DBCC SHRINKFILEкоманду.

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

Кращі практики

Враховуйте наступну інформацію, коли ви плануєте зменшити файл:

  • Операція скорочення є найбільш ефективною після операції, яка створює багато невикористаного простору, наприклад, обрізання таблиці або операція з випаданням таблиці.
  • Більшість баз даних потребують вільного місця для регулярних щоденних операцій. Якщо ви скорочуєте базу даних неодноразово і помічаєте, що розмір бази даних знову збільшується, це вказує на те, що простір, який було скорочено, потрібно для регулярних операцій. У цих випадках багаторазове скорочення бази даних є марною операцією.
  • Операція скорочення не зберігає стан фрагментації індексів у базі даних і, як правило, збільшує фрагментацію до певної міри. Це ще одна причина не повторно скорочувати базу даних.
  • Стискайте кілька файлів у одній базі даних послідовно, а не одночасно. Суперечка в системних таблицях може спричинити затримки через блокування.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.