Управление файловым пространством для баз данных в базе данных База данных SQL Azure

Применимо к: База данных SQL Azure

В этой статье описаны различные типы дискового пространства для баз данных в Базе данных SQL Azure. Иногда вам может придётся специально управлять выделенным файловым пространством. В этой статье приведены шаги для этого.

Обзор

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

Возможно, вам придётся уменьшить файлы данных и вернуть неиспользуемое пространство в следующих сценариях:

  • Обеспечить рост данных для баз данных в эластичном пуле, когда большое выделенное пространство для некоторых баз данных в пуле приводит к приближению к максимальному размеру пула.
  • Чтобы позволить уменьшить максимальный размер одной базы данных или эластичного пула.
  • Изменить базу данных или эластичный пул на уровень с более низким максимальным лимитом размера.
  • Для снижения затрат на хранение при использовании уровня сервиса Hyperscale.

Внимание

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

Мониторинг использования пространства файлов

API Azure Resource Manager (ARM), включая PowerShell get-metrics, возвращают объем используемого и выделенного пространства для баз данных и эластичных пулов.

Следующие системные представления также возвращают размер используемого и выделенного пространства для баз данных и эластичных пулов:

Общие сведения о типах дискового пространства для базы данных

Понимание следующих объемов дискового пространства важно для управления файловыми пространствами базы данных.

Объем пространства базы данных Определение Комментарии
Место, занятое данными Объём пространства, используемого для хранения данных. Как правило, используемое пространство увеличивается (уменьшается) при операциях вставки (удаления). В некоторых случаях используемое пространство не изменяется при вставке или удалении в зависимости от объема и шаблона данных, участвующих в операции, и любого фрагментации. Например, удаление одной строки на каждой странице данных не обязательно приведет к уменьшению используемого пространства.
Выделенное пространство данных Объём хранилища, занимаемого файлами данных. Объем выделенного пространства увеличивается автоматически, но никогда не уменьшается автоматически после удаления. Такое поведение обеспечивает ускорение будущих вставок, поскольку пространство не требует перераспределения.
Выделенное, но неиспользуемое пространство данных Разница между объемом выделенного и используемого пространства данных. Это количество представляет максимальный объем свободного пространства, которое можно освободить путем сжатия файлов данных базы данных.
Максимальный размер данных Максимальное пространство, которое можно использовать для хранения данных. Объем выделенного пространства данных не может превышать максимальный объем данных.

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

Схема, демонстрирующая разницу в размерах концепций пространства базы данных в таблице параметров объема баз данных.

Запрос одной базы данных для сведений о пространстве файлов

Используйте следующий запрос на sys.database_files , чтобы вернуть объем выделенного места в файле базы данных и объем неиспользуемого пространства.

-- Connect to a user database
SELECT file_id,
       type_desc,
       CAST (FILEPROPERTY(name, 'SpaceUsed') AS DECIMAL (19, 4)) * 8 / 1024. AS space_used_mb,
       CAST (size / 128.0 - CAST (FILEPROPERTY(name, 'SpaceUsed') AS INT) / 128.0 AS DECIMAL (19, 4)) AS space_unused_mb,
       CAST (size AS DECIMAL (19, 4)) * 8 / 1024. AS space_allocated_mb,
       CAST (max_size AS DECIMAL (19, 4)) * 8 / 1024. AS max_size_mb
FROM sys.database_files;

Общие сведения о типах дискового пространства для эластичного пула

Понимание следующих величин пространства хранения важно для управления файловым пространством эластичного пула.

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

Сообщение об ошибке «Эластичный пул достиг предела памяти» указывает, что объекты базы данных занимают достаточно места, чтобы соответствовать максимальному размеру памяти эластичного пула. Рассмотрите возможность увеличения лимита хранилища или освободите место для данных, как описано в разделе Освобождение неиспользуемого выделенного пространства.

Запрос эластичного пула для получения сведений о дисковом пространстве

Используйте следующие запросы для определения размеров пространства хранения для эластичного пула.

Используемое пространство данных эластичного пула

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

-- Connect to master
SELECT TOP (1) avg_storage_percent / 100.0 * elastic_pool_storage_limit_mb AS elastic_pool_space_used_mb,
               avg_allocated_storage_percent / 100.0 * elastic_pool_storage_limit_mb AS elastic_pool_space_allocated_mb,
               elastic_pool_storage_limit_mb AS elastic_pool_maximum_size_mb
FROM sys.elastic_pool_resource_stats
WHERE elastic_pool_name = 'ep1'
ORDER BY end_time DESC;

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

Внимание

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

Сжатие файлов данных

Поскольку уменьшение файлов данных может влиять на производительность базы данных, База данных SQL Azure не автоматически уменьшает файлы данных. При необходимости вы можете уменьшить файлы данных по выбранному вам времени. Не следует выполнять shrink как регулярно запланированную операцию. Вместо этого рассмотрите возможность использовать его только после значительного сокращения используемого пространства.

Совет

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

Чтобы уменьшить файлы, используйте команду DBCC SHRINKDATABASE или DBCC SHRINKFILE T-SQL:

  • DBCC SHRINKDATABASE Уменьшает все данные и файлы журналов в базе данных одной командой. Команда сжимает по одному файлу данных за раз, что может занять много времени для больших баз данных. Она также сжимает файл журнала, что обычно не требуется, так как База данных SQL Azure автоматически сжимает файлы журнала по мере необходимости.
  • DBCC SHRINKFILE команда поддерживает более сложные сценарии:
    • При необходимости она может применяться к отдельным файлам, а не для сжатия всех файлов в базе данных.
    • Каждая команда DBCC SHRINKFILE может выполняться параллельно с другими командами DBCC SHRINKFILE, чтобы сократить общее время операции shrink, однако это приводит к повышенному потреблению ресурсов и увеличивает вероятность временной блокировки пользовательских запросов и других параллельно выполняемых команд DBCC SHRINKFILE.
    • Если хвост файла не содержит данных, вы можете уменьшить размер выделенного файла быстрее, указав аргумент TRUNCATEONLY . TRUNCATEONLY не требует перемещения данных внутри файла, но и не так сильно уменьшает выделенный размер.
  • Дополнительные сведения об этих командах сжатия см. в статьях DBCC SHRINKDATABASE и DBCC SHRINKFILE.

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

Для использования DBCC SHRINKDATABASE для сжатия всех файлов данных и журналов в заданной базе данных, воспользуйтесь следующей командой:

DBCC SHRINKDATABASE (N'database_name');

База данных может содержать один или несколько файлов данных, которые автоматически создаваются по мере роста данных. Чтобы определить структуру вашей базы данных, включая используемый и выделенный размер каждого файла, выполните запрос к sys.database_files представлению каталога с помощью следующего примера скрипта:

-- Review file properties, including the file_id and name values to use in shrink commands
SELECT file_id,
       name,
       CAST (FILEPROPERTY(name, 'SpaceUsed') AS BIGINT) * 8 / 1024. AS space_used_mb,
       CAST (size AS BIGINT) * 8 / 1024. AS space_allocated_mb,
       CAST (max_size AS BIGINT) * 8 / 1024. AS max_file_size_mb
FROM sys.database_files
WHERE type_desc IN ('ROWS', 'LOG');

Чтобы уменьшить один файл, используйте DBCC SHRINKFILE команду, например:

-- Shrink database data file named 'data_0` by removing all unused at the end of the file, if any.
DBCC SHRINKFILE ('data_0', TRUNCATEONLY);

Сжатие файла журнала транзакций

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

На уровнях службы Premium и Business Critical, если журнал транзакций увеличится, это может существенно увеличить использование локального хранилища, приближая его к пределу максимального объема локального хранилища. Если использование локального хранилища приближается к пределу, вы можете сжать журнал транзакций с помощью команды DBCC SHRINKFILE, как показано в следующем примере. Локальное хранилище освобождается сразу после завершения команды, не дожидаясь периодической операции автоматического сжатия.

Выполните следующий пример, подключившись к целевой пользовательской базе данных, а не к базе данных master.

-- Shrink the database log file (always file_id 2), by removing all unused space at the end of the file, if any.
DBCC SHRINKFILE (2, TRUNCATEONLY);

Автоматическое сжатие

В качестве альтернативы сжатию файлов данных вручную можно включить автоматическое сжатие для базы данных. Однако автоматическое сжатие может быть менее эффективным при восстановлении файлового пространства, чем операции DBCC SHRINKDATABASE и DBCC SHRINKFILE.

По умолчанию автоматическое сжатие отключено, что рекомендуется для большинства баз данных. Если возникает необходимость включить автоматическое сжатие, рекомендуется отключить его после достижения целей по управлению пространством, а не оставлять его включённым постоянно. Дополнительные сведения см. в разделе Рекомендации для AUTO_SHRINK.

Например, автоматическое сжатие может быть полезно, если эластичный пул содержит множество баз данных, объём используемого пространства в которых то значительно увеличивается, то уменьшается, из-за чего пул приближается к своему максимальному размеру. Этот сценарий не распространен.

Опция автоматического уменьшения базы данных не действует в гипермасштабных базах данных.

Чтобы включить автоматическое сжатие, выполните следующую команду при подключении к вашей базе данных (а не master базе данных).

-- Enable auto-shrink for the current database.
ALTER DATABASE CURRENT
    SET AUTO_SHRINK ON;

Для получения дополнительной информации об этой команде см. опции DATABASE SET.

Обслуживание индекса после уменьшения

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

Дополнительные сведения об обслуживании индексов см. в статье Оптимизация обслуживания индексов для повышения производительности запросов и снижения потребления ресурсов.

Сжатие больших баз данных

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

Совет

ShrinkDriver — это скрипт PowerShell, который автоматизирует и упрощает процесс уменьшения для больших баз данных, превращая его в единую, наблюдаемую и вособновляемую операцию. Скрипт сжимает несколько файлов параллельно, повторяет попытки при прерывании и выводит подробные отчёты о состоянии по мере запуска.

Фиксация базовых показателей использования пространства

Перед началом сжатия зафиксируйте текущее используемое и выделенное пространство в каждом файле базы данных, выполнив следующий запрос на использование пространства:

SELECT file_id,
       CAST (FILEPROPERTY(name, 'SpaceUsed') AS BIGINT) * 8 / 1024. AS space_used_mb,
       CAST (size AS BIGINT) * 8 / 1024. AS space_allocated_mb,
       CAST (max_size AS BIGINT) * 8 / 1024. AS max_size_mb
FROM sys.database_files
WHERE type_desc = 'ROWS';

После завершения сжатия вы можете снова выполнить этот запрос и сравнить результат с исходными базовыми показателями.

Усекайте файлы данных для быстрого, но ограниченного усиления

Если вы хотите быстро добиться некоторого уменьшения объёма выделенного пространства, рассмотрите возможность выполнения DBCC SHRINKFILE с параметром TRUNCATEONLY. Если в конце файла есть выделенное, но неиспользуемое пространство, операция быстро удаляет это пространство без перемещения данных.

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

Следующий пример команды усекает ID файла 4:

DBCC SHRINKFILE (4, TRUNCATEONLY);

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

Определение плотности страницы индекса

В качестве необязательного, но рекомендуемого шага определить среднюю плотность страниц индексов в базе данных. При одинаковом объёме данных операции сжатия завершаются быстрее при высокой плотности страниц, поскольку при этом в каждом файле перемещается меньше страниц. Если плотность страниц для некоторых индексов низкая, рассмотрите возможность выполнения обслуживания этих индексов, чтобы повысить плотность страниц, прежде чем сжимать файлы данных. Более высокая плотность страниц позволяет операции shrink добиться более значительного сокращения выделенного дискового пространства.

Чтобы определить плотность страниц для всех индексов в базе данных, используйте следующий запрос. Плотность страницы указывается в столбце avg_page_space_used_in_percent.

SELECT OBJECT_SCHEMA_NAME(ips.object_id) AS schema_name,
       OBJECT_NAME(ips.object_id) AS object_name,
       i.name AS index_name,
       i.type_desc AS index_type,
       ips.avg_page_space_used_in_percent,
       ips.avg_fragmentation_in_percent,
       ips.page_count,
       ips.alloc_unit_type_desc,
       ips.ghost_record_count
FROM sys.dm_db_index_physical_stats(DB_ID(), DEFAULT, DEFAULT, DEFAULT, 'SAMPLED') AS ips
     INNER JOIN sys.indexes AS i
         ON ips.object_id = i.object_id
        AND ips.index_id = i.index_id
ORDER BY page_count DESC;

Если есть индексы с большим количеством страниц (как указано в page_count столбце) с плотностью страниц ниже 60-70%, рассмотрите возможность перестройки или реорганизации этих индексов перед уменьшением файлов данных.

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

Если есть несколько индексов с низкой плотностью страниц, вы можете перестроить их параллельно на нескольких сеансах базы данных, чтобы ускорить процесс. Однако убедитесь, что вы не приближаетесь к лимиту ресурсов базы данных. Оставьте достаточный резерв ресурсов для рабочих нагрузок приложений, которые могут быть запущены. Отслеживайте потребление ресурсов (CPU, Data IO, Log IO) в портале Azure или с помощью представления sys.dm_db_resource_stats. Начинайте дополнительные операции с индексированием только в том случае, если использование ресурсов по каждому из этих измерений значительно ниже 100%.

Пример команды восстановления индекса

Следующий пример команды использует оператор ALTER INDEX для восстановления индекса и увеличения плотности страниц:

ALTER INDEX [index_name] ON [schema_name].[table_name]
REBUILD WITH (
    FILLFACTOR = 100, MAXDOP = 8, ONLINE = ON (
        WAIT_AT_LOW_PRIORITY (MAX_DURATION = 5 MINUTES, ABORT_AFTER_WAIT = NONE)),
    RESUMABLE = ON
);

Эта команда инициирует перестроение индекса в онлайн-режиме с возможностью возобновления. Эта операция позволяет параллельным рабочим нагрузкам продолжать использовать таблицу, пока выполняется перестроение, и позволяет возобновить перестроение, если он прерывается по какой-либо причине. Но такой тип перестроения медленнее перестроения в режиме оффлайн, которое блокирует доступ к таблице. Если другим рабочим нагрузкам не требуется доступ к таблице во время перестроения, задайте для параметров ONLINE и RESUMABLE значение OFF и удалите предложение WAIT_AT_LOW_PRIORITY.

Дополнительные сведения об обслуживании индексов см. в статье Оптимизация обслуживания индексов для повышения производительности запросов и снижения потребления ресурсов.

Реорганизуйте индексы перед уменьшением

Реорганизация индексов перед уменьшением может значительно ускорить операцию уменьшения в двух сценариях.

  1. Если база данных соответствует всем следующим критериям:

    • В нём большое количество файлов данных (более 10).
    • В базе данных имеется большое количество таблиц (несколько сотен и более), которые вместе занимают большое пространство (сотни гигабайт и более).
    • Большое количество данных удаляется из некоторых таблиц.

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

  2. Если база данных содержит:

    • Крупные типы данных объектов (LOB), такие как varchar(max),nvarchar(max),varbinary(max),xml или аналогичные типы данных, хранятся в блоке LOB_DATA распределения.
    • Большие строки , хранящиеся в единице ROW_OVERFLOW_DATA выделения.
    • Индексы Columnstore.

    Чтобы ускорить работу shrink и освободить больше места в этом сценарии, обязательно включите клаузу LOB_COMPACTION при реорганизации индексов. Сжатие LOB перед уменьшением рекомендуется для всех индексов, содержащих столбцы LOB или большие строки.

    Реорганизация или перестроение индексов columnstore перед сжатием может также увеличить скорость сжатия и эффективность.

В следующем примере показана команда для реорганизации индекса и выполнения сжатия LOB:

ALTER INDEX [index_name] ON [schema_name].[table_name]
REORGANIZE WITH(LOB_COMPACTION = ON);

Сжатие нескольких файлов данных параллельно

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

Следующий пример команды уменьшает ID файла 4, пытаясь уменьшить его выделенный размер до 52 000 МБ:

DBCC SHRINKFILE (4, 52000);

Чтобы сократить выделенное пространство для файла до минимально возможного, выполните оператор без указания размера цели:

DBCC SHRINKFILE (4);

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

Уменьшайтесь постепенно

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

Чтобы избежать этой проблемы, уменьшайте каждый файл постепенно и постепенно. В команде задайте целевой объект, который меньше текущего выделенного пространства для файла, но больше используемого пространства, которое возвращает запрос по DBCC SHRINKFILEиспользованию базового пространства .

Например, если выделенное место для ID файла 4 составляет 200 000 МБ, и вы хотите уменьшить его до 100 000 МБ, сначала можно установить цель на 180 000 МБ:

DBCC SHRINKFILE (4, 180000);

После того как эта команда уменьшает выделенный размер до 180 000 МБ, можно снова запустить уменьшение, сначала установив цель на 160 000 МБ, затем на 140 000 МБ, и продолжать уменьшать цель, пока файл не достигнет нужного размера.

Уменьшение файлов постепенно может занять больше времени, но снижает риск повторения сжатия для всего файла из-за неожиданного прерывания.

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

Мониторинг операций сжатия

Для мониторинга прогресса уменьшения для всех одновременных сессий уменьшения используйте следующий запрос:

SELECT command,
       percent_complete,
       status,
       wait_resource,
       session_id,
       wait_type,
       blocking_session_id,
       cpu_time,
       reads,
       writes,
       CAST (((DATEDIFF(s, start_time, GETDATE())) / 3600) AS VARCHAR) + ' hour(s), '
               + CAST ((DATEDIFF(s, start_time, GETDATE()) % 3600) / 60 AS VARCHAR) + 'min, '
               + CAST ((DATEDIFF(s, start_time, GETDATE()) % 60) AS VARCHAR) + ' sec'
           AS running_time
FROM sys.dm_exec_requests AS r
     LEFT OUTER JOIN sys.databases AS d
         ON r.database_id = d.database_id
WHERE r.command IN ('DbccSpaceReclaim', 'DbccFilesCompact', 'DbccLOBCompact', 'DBCC');

Примечание.

Прогресс по уменьшению может быть нелинейным, и значение в percent_complete столбце может оставаться неизменным длительное время, даже если уменьшение всё ещё продолжается. Увеличение значений cpu_time, reads или writes для одного и того же session_id между двумя выполнениями запроса означает, что сжатие продолжает продвигаться.

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

Временные ошибки во время сжатия

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

Сценарий PowerShell ShrinkDriver автоматически повторяет попытку сжатия при возникновении временной ошибки. Используйте этот скрипт для уменьшения больших баз данных.

Следующий пример T-SQL скрипта показывает, как запустить уменьшение для одного файла в цикле повторного тестирования. Цикл автоматически повторяет операцию до заданного числа раз при возникновении ошибки тайм-аута или ошибки взаимной блокировки. Этот подход с повторной попыткой подходит и для многих других ошибок, которые могут возникнуть во время сжатия.

DECLARE @RetryCount AS INT = 3; -- adjust to configure desired number of retries
DECLARE @Delay AS CHAR (12);

-- Retry loop
WHILE @RetryCount >= 0
BEGIN
    BEGIN TRY
        DBCC SHRINKFILE (1); -- adjust file_id and other shrink parameters

        -- Exit retry loop on successful execution
        SELECT @RetryCount = -1;

    END TRY
    BEGIN CATCH
        -- Retry for the declared number of times without raising
        -- an error if deadlocked or timed out waiting for a lock
        IF ERROR_NUMBER() IN (1205, 49516) AND @RetryCount > 0
        BEGIN
            SELECT @RetryCount -= 1;

            PRINT CONCAT('Retry at ', SYSUTCDATETIME());

            -- Wait for a random period of time between 1 and 10 seconds before retrying
            SELECT @Delay = '00:00:0' + CAST (CAST (1 + RAND() * 8.999 AS DECIMAL (5, 3)) AS VARCHAR (5));

            WAITFOR DELAY @Delay;

        END
        ELSE -- Raise error and exit loop
        BEGIN
            SELECT @RetryCount = -1;

            THROW;

        END
    END CATCH
END

Помимо тайм-аутов и тупиков, shrink может столкнуться с ошибками из-за известных проблем.

Ознакомьтесь с ошибками и мерами по устранению последствий в следующих разделах.

Ошибка номер 49503

%.*ls: Page %d:%d could not be moved because it is an off-row persistent version store page. Page holdup reason: %ls. Page holdup timestamp: %I64d.

Эта ошибка возникает, когда длительные активные транзакции генерируют версии строк в хранилище постоянных версий (PVS). Shrink не может перемещать страницы с версиями строк.

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

Дополнительные сведения о диагностике и устранении неполадок, связанных с задержками очистки PVS, которые могут повлиять на сжатие, см. в разделе «Мониторинг и устранение неполадок ускоренного восстановления базы данных».

Ошибка номер 5223

%.*ls: Empty page %d:%d could not be deallocated.

Эта ошибка может возникнуть во время текущих операций обслуживания индекса, таких как ALTER INDEX. Повторите команду сжатия после завершения этих операций.

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

SELECT OBJECT_SCHEMA_NAME(pg.object_id) AS schema_name,
       OBJECT_NAME(pg.object_id) AS object_name,
       i.name AS index_name,
       p.partition_number
FROM sys.dm_db_page_info(DB_ID(), <file_id>, <page_id>, default) AS pg
INNER JOIN sys.indexes AS i
ON pg.object_id = i.object_id
   AND
   pg.index_id = i.index_id
INNER JOIN sys.partitions AS p
ON pg.partition_id = p.partition_id;

Перед выполнением этого запроса замените заполнители <file_id> и <page_id> фактическими значениями из сообщения об ошибке. Например, если сообщение выглядит так: Empty page 1:62669 could not be deallocated, то <file_id> — это 1, а <page_id> — это 62669.

Перестройте индекс, определенный запросом, и повторите команду сжатия.

Ошибка номер 5201

DBCC SHRINKDATABASE: File ID %d of database ID %d was skipped because the file does not have enough free space to reclaim.

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