Многие технические специалисты 1С сталкиваются с парадоксальной ситуацией: при попытке очистить базу данных от старых записей в регистрах накопления объем файлов на диске не уменьшается, а, наоборот, начинает стремительно расти. Ситуация усугубляется, когда штатное «Тестирование и исправление» (ТиИ) приводит к удвоению размера базы, вызывая нехватку дискового пространства и аварийную остановку систем. В рамках этой статьи мы подробно разберем внутренние механизмы работы 1С и SQL Server, выясним причины такого поведения и составим алгоритм правильного удаления данных.
Для начала проанализируем, что происходит в SQL Server, когда 1С выполняет запись пустого набора записей по регистратору. На уровне системы управления базами данных инициируется команда DELETE. Однако физического удаления байтов с диска в этот момент не происходит. Рассмотрим ключевые причины «раздувания» файлов:
Ghost Cleanup должен очистить эти записи позже. Если мы удаляем данные массово и в цикле, этот процесс просто не успевает за нашими действиями, и база продолжает хранить фактически «мертвые» данные вместе с новыми служебными структурами.Full (Полная) и бэкапы лога выполняются редко.Page Split (расщепление страницы), создавая новые страницы там, где старые еще не были полностью освобождены. В результате индекс может стать значительно объемнее, чем был до начала очистки.Проанализируем структуру регистра накопления. Он состоит не только из таблицы движений (_AccumRg), но и из таблиц итогов (_AccumRgT). Когда мы записываем пустой набор записей, используя следующий код:
НаборЗаписей = РегистрыНакопления.ЗаказыПокупателей.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДТ.Регистратор);
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Записать(Истина);
Система 1С вынуждена скорректировать итоги. Если удаляются старые периоды, в таблицах итогов происходит множество операций UPDATE или INSERT для корректировки остатков и оборотов. Это порождает колоссальную нагрузку на дисковую подсистему и взрывной рост логов. При использовании флага ОбменДанными.Загрузка = Истина отключаются прикладные проверки, но физические операции с таблицами итогов на уровне SQL никуда не исчезают.
Выясним причину, по которой штатные средства 1С требуют так много места. В процессе ТиИ при выборе пункта «Реиндексация таблиц» или «Пересчет итогов», SQL Server часто пересоздает индексы целиком. Для выполнения операции ALTER INDEX REBUILD системе требуется временно создать новую структуру индекса рядом со старой. Если ваша таблица занимает 100 ГБ, то в моменте выполнения операции ей потребуется еще около 100 ГБ свободного места в файле данных. Именно поэтому на дисках с малым запасом места ТиИ завершается ошибкой.
Чтобы процесс очистки прошел эффективно и не привел к остановке системы, рекомендуем придерживаться следующего алгоритма:
Ghost Cleanup.Simple (Простая). Это предотвратит бесконтрольный рост файла .LDF. После завершения работ верните модель Full и сделайте полный бэкап._AccumRgT.Shrink (сжатия), которое крайне негативно влияет на производительность из-за дикой фрагментации, выполните операции REORGANIZE или REBUILD для индексов наиболее крупных таблиц. Это переупакует данные и позволит SQL Server использовать освободившееся внутри файла место для новых записей без расширения самого файла .MDF.Посмотрим на пример кода, который выполняет удаление порциями с фиксацией транзакций, что позволяет системе «дышать» в процессе работы:
Выборка = Документы.ЗаказПокупателя.Выбрать(ДатаНачала, ДатаОкончания);
Счетчик = 0;
Пока Выборка.Следующий() Цикл
НаборЗаписей = РегистрыНакопления.ЗаказыПокупателей.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Выборка.Ссылка);
// Использование Загрузка = Истина ускоряет процесс, отключая подписки
НаборЗаписей.ОбменДанными.Загрузка = Истина;
Попытка
НаборЗаписей.Записать(Истина);
Счетчик = Счетчик + 1;
Исключение
ЗаписьЖурналаРегистрации("Ошибка удаления", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
// Каждые 500 записей даем СУБД обработать транзакции
Если Счетчик % 500 = 0 Тогда
// Здесь можно вставить небольшую паузу или просто зафиксировать прогресс
ОбработкаПрерыванияПользователя();
КонецЕсли;
КонецЦикла;
Проанализировав ситуацию, можно сделать вывод, что рост базы при удалении — это естественный процесс работы страниц данных и индексов SQL Server. Важно помнить: размер файла базы данных — это не только объем самих данных, но и зарезервированное место, которое СУБД будет использовать в будущем. Если вы планируете продолжать работу в этой базе, не стремитесь во что бы то ни стало «сжать» файл до минимальных размеров. Вместо этого сфокусируйтесь на регламентном обслуживании индексов и контроле за ростом таблиц итогов.
Если же ваша цель — физически уменьшить размер базы (например, для передачи копии), то последовательность должна быть такой: Удаление данных -> Очистка итогов -> Rebuild индексов -> Shrink (только в этом случае!) -> Full Backup.