VLF — это виртуальные файлы журнала. Пока их немного, они тихо делают свою работу. Но стоит им расплодиться, как журнал транзакций начинает напоминать коммунальную квартиру с бесконечными чуланами: нужную коробку вроде бы видно, а чтобы до неё добраться, приходится открывать дверь за дверью.
Чем больше VLF, тем заметнее просадка производительности. Страдают, причём дружно, почти все участники процесса:
- резервное копирование журнала — вместо одного крупного блока приходится перебирать гору мелких;
- восстановление базы данных — и без того не мгновенное, с массой VLF превращается в марафон;
- очистка журнала и его усечение — буксует из-за фрагментации;
- репликация — агент чтения журнала пробирается через дебри VLF, доставка изменений замедляется;
- восстановление после сбоя — система приходит в себя дольше;
- откаты транзакций — процедура становится ещё томительнее;
- обычные операции изменения данных — даже они ощущают на себе тяжесть раздробленного журнала;
- запуск базы данных — при миллионах мелких VLF старт может затянуться.
Порогом тревоги обычно считают тысячу VLF, хотя некоторые умудряются довести журнал до полутора миллионов. Это уже не повод для гордости, а повод взяться за настройки.
Хорошая новость с оговоркой
В SQL Server 2022 (16.x) и более поздних версиях появилось послабление: при автоувеличении журнала новый кусок можно не перезаписывать нулями, если его размер не превышает 64 МБ. Это та самая мгновенная инициализация файлов, которая для файлов данных работает давно, а до журнала добралась только сейчас.
Но есть нюанс, и он принципиальный: если вы настроили автоувеличение журнала на 65 МБ или больше, обнуление никуда не денется — SQL Server честно затрёт новый кусок нулями, и операция снова станет медленной. Так что «волшебная палочка» работает только в пределах 64 МБ. Для журнала эта функция не требует прав SE_MANAGE_VOLUME_NAME, которые нужны для файлов данных, но включённая мгновенная инициализация на экземпляре всё равно должна быть в наличии.
Контрольная точка — не уборщик, а диспетчер
Контрольная точка (CHECKPOINT) сама по себе в журнале ничего не удаляет и не усекает. Её задача — сбросить на диск грязные страницы данных и служебные метаданные базы, которые накопились в памяти. Пока эти страницы не зафиксированы на диске, соответствующие записи журнала остаются нужными для восстановления — а значит, и VLF, в которых они лежат, может оказаться невозможно пометить как неактивные.
Вот тут и вступает в игру MinLSN — минимальный номер последовательности в журнале, необходимый для успешного отката или восстановления. Контрольная точка записывает этот MinLSN в служебную страницу базы данных (boot page). Всё, что в журнале находится до MinLSN, после успешной контрольной точки становится ненужным для восстановления — и соответствующие VLF можно пометить как неактивные (inactive), то есть пригодные для повторного использования.
Именно поэтому shrink журнала без предварительной контрольной точки — занятие не всегда эффективное: журнал может быть полон «мёртвым грузом» с точки зрения физического места, но с точки зрения логики восстановления эти VLF всё ещё активны.
Дальше всё зависит от модели восстановления:
- в простой модели сразу же после сброса грязных страниц контрольной точкой те VLF, что оказались до MinLSN, становятся неактивные. Это и есть то, что на бытовом уровне называют «очисткой журнала»;
- в полной модели контрольная точка только фиксирует MinLSN и сбрасывает страницы, но это не приводит к повторному использованию VLF. Разрешение появляется лишь после резервной копии журнала — именно она сдвигает границу и позволяет помечать VLF как неактивные.
Так что в полной модели цикл получается двухступенчатым: контрольная точка подготавливает почву (сбрасывает грязные страницы), а резервная копия журнала даёт «добро» на освобождение VLF. Без резервной копии журнала в полной модели VLF так и останутся активными, сколько бы контрольных точек вы ни выполняли и DBCC SHRINKFILE не сделает той работы, которую от него ожидают. Но даже если всё сделано правильно, длинные транзакции могут помешать высвобождению LSN в конце файла и размер может сразу не измениться. Однако, повторяя этот цикл, можно постепенно уменьшить физический размер файла, а также количество VLF в нём.
Как снизить количество VLF и не довести журнал до фрагментации
- не мельчить с автоувеличением: рост по 10% или маленькими кусками гарантированно плодит VLF;
- задать автоувеличению фиксированный размер, например 64 МБ, чтобы попасть в новое послабление, или 1 ГБ и больше — если вы готовы платить за обнуление, но получить меньше VLF за один шаг;
- увеличивать журнал вручную до разумного размера, а не ждать очередного мелкого роста;
- следить за количеством VLF через
DBCC LOGINFOилиsys.dm_db_log_info; - при сильной фрагментации — аккуратно усечь файл журнала: выполнить контрольную точку, чтобы сбросить грязные страницы и зафиксировать MinLSN, а в полной модели — обязательно сделать резервную копию журнала, затем сжать файл командой
DBCC SHRINKFILEи повторять этот цикл, пока количество VLF не снизится до приемлемого. Обычно хватает двух–трёх итераций, если нет длинных незавершённых транзакций, репликации или других факторов, удерживающих журнал; - не увлекаться уменьшением журнала без нужды — потом рост опять наделает мелких VLF.
В SQL Server 2014 и 2022 алгоритмы создания VLF улучшили, но расслабляться не стоит: доверяй, но проверяй. Мониторьте количество VLF — и журнал не превратится в бесконечную коммуналку.
Полезные ссылки:
- Руководство Microsoft по архитектуре журнала транзакций
- VLF в SQL Server 2014
- SQL Server 2022 и VLF
- Начальные номера последовательностей VLF и размер файла журнала по умолчанию
- О VLF и журнале транзакций
- SQL Server и VLF: часть 1
- SQL Server и VLF: часть 2
- SQL Server и VLF: часть 3
- SQL Server и VLF: часть 4
- Проблемы конфигурации журнала транзакций
- VLF: продолжение
- VLF: ещё продолжение
- IOCompletion и WriteCompletion

Комментариев нет:
Отправить комментарий