При обслуживании баз данных MS SQL Server администраторы регулярно сталкиваются с ситуацией, когда файл журнала транзакций (.ldf) разрастается до огромных размеров и значительно превышает размер самого файла данных (.mdf). Стандартный алгоритм решения этой задачи кажется простым: перевести базу данных в простую модель восстановления (SIMPLE) и выполнить процедуру сжатия файла (DBCC SHRINKFILE). Однако бывают случаи, когда файл лога сжимается лишь на пару мегабайт или не уменьшается вовсе, выдавая сообщение о том, что все логические файлы журналов находятся в использовании.
Рассмотрим подробно причины возникновения такой проблемы, разберем по шагам диагностику и проанализируем способы принудительной очистки журнала транзакций.
Журнал транзакций внутри состоит из виртуальных файлов журнала (Virtual Log Files, или VLF). SQL Server не может усечь или сжать файл .ldf, если VLF удерживаются определенными процессами СУБД. Чтобы понять, какой именно процесс блокирует повторное использование и сжатие пространства, проанализируем системные представления SQL Server.
Выполним следующую последовательность диагностических шагов:
DBCC SQLPERF(logspace);
sys.databases:
SELECT name, recovery_model_desc, log_reuse_wait, log_reuse_wait_desc
FROM sys.databases
WHERE name = 'Имя_Вашей_Базы';
Если в поле log_reuse_wait_desc возвращается значение REPLICATION (значение log_reuse_wait = 6), это означает, что SQL Server ожидает чтения журнала агентом репликации. Подобная ситуация часто возникает на тестовых базах или базах разработки, созданных путем восстановления из рабочей копии: репликация в новой базе фактически не настроена и не работает, но системный флаг остался перенесенным из оригинала.
Пока СУБД считает, что транзакции ожидают передачи в реплику, она не позволит очистить неактивные VLF. Чтобы снять заблокированные транзакции и очистить статус репликации, необходимо выполнить системную процедуру sp_removedbreplication.
Разберем по шагам алгоритм решения задачи:
master и сбросим настройки репликации для целевой базы данных:
USE master;
GO
EXEC sp_removedbreplication @dbname = 'Имя_Вашей_Базы';
GO
sys.databases:
SELECT name, log_reuse_wait_desc
FROM sys.databases
WHERE name = 'Имя_Вашей_Базы';
log_reuse_wait_desc должно измениться на NOTHING или CHECKPOINT.
USE [Имя_Вашей_Базы];
GO
ALTER DATABASE [Имя_Вашей_Базы] SET RECOVERY SIMPLE;
GO
CHECKPOINT;
GO
-- Указываем логическое имя файла журнала и целевой размер в мегабайтах
DBCC SHRINKFILE ('Имя_Файла_Лога', 100);
GO
FULL) и создадим полный бэкап базы данных:
ALTER DATABASE [Имя_Вашей_Базы] SET RECOVERY FULL;
GO
Если после снятия флага репликации файл журнала всё еще не сжимается до желаемого размера, рассмотрим другие возможные факторы:
1. Включенная технология Change Data Capture (CDC)
Технология отслеживания изменений CDC использует тот же механизм сканирования журнала, что и транзакционная репликация. Если CDC был включен в исходной базе, в log_reuse_wait_desc также может отображаться status REPLICATION. Если отслеживание изменений больше не требуется, отключим его командой:
USE [Имя_Вашей_Базы];
GO
EXEC sys.sp_cdc_disable_db;
GO
2. Активный VLF находится в конце файла
Команда DBCC SHRINKFILE не может уменьшить файл за пределы физического расположения последнего активного VLF. Если транзакция зафиксировалась в самом конце файла лога, сжатие не сработает. Чтобы сместить указатель активного VLF в начало файла:
SIMPLE.CHECKPOINT.DBCC SHRINKFILE.3. Пересоздание журнала через Detach / Attach (для экстренных случаев)
Если базу данных можно временно монопольно отключить от пользователей, пересоздадим файл журнала полностью:
EXEC sp_detach_db 'Имя_Вашей_Базы';.ldf на диске.
CREATE DATABASE [Имя_Вашей_Базы] ON
( FILENAME = N'C:\SQLData\mydb.mdf' )
FOR ATTACH_REBUILD_LOG;
Таким образом, своевременная диагностика через sys.databases и очистка устаревших статусов репликации позволяют быстро вернуть контроль над размером журнала транзакций без риска повреждения структуры базы данных.