При свертке крупных информационных баз 1С стандартная процедура удаления движений документов штатными методами может занимать дни или даже недели. В связи с этим часто возникает задача ускорить процесс и очистить устаревшие записи регистров накопления напрямую через СУБД (SQL). Разберем, как устроен этот процесс, какие шаги необходимо выполнить, с какими скрытыми рисками можно столкнуться и как правильно обслужить базу данных после прямой модификации таблиц.
Если требуется очистить таблицу регистра не полностью, а только за определенный период (например, отрезать прошлые годы, предварительно сформировав документы ввода начальных остатков на дату среза), команда TRUNCATE TABLE не подойдет, так как она полностью стирает содержимое таблицы. В этом случае применяется инструкция DELETE. Рассмотрим пошаговый алгоритм действий:
ПолучитьСтруктуруХраненияБазыДанных() в 1С определяем физические имена таблиц регистра движений и таблицы итогов в SQL.Посмотрим на пример получения имени таблицы в 1С:
Структура = ПолучитьСтруктуруХраненияБазыДанных("РегистрНакопления.ТоварыНаСкладах");
ИмяТаблицыДвижений = Структура[0].ИмяТаблицыХранения;
Сообщить("Имя таблицы в SQL: " + ИмяТаблицыДвижений);
При удалении больших объемов данных через SQL важно не выполнять удаление всего массива одной командой DELETE FROM ... WHERE ..., так как это приведет к резкому разрастанию файла журнала транзакций (LDF) и эскалации блокировок. Разберем пример порционного (батчевого) удаления записей в цикле:
DECLARE @RowsDeleted INT = 1;
WHILE (@RowsDeleted > 0)
BEGIN
DELETE TOP (50000) FROM _AccumRg1234
WHERE _Period < '2023-01-01 00:00:00';
SET @RowsDeleted = @@ROWCOUNT;
CHECKPOINT; -- При необходимости для Simple Recovery Model
END;
Прямое вмешательство в таблицы СУБД в обход объектной модели 1С влечет за собой несколько критических рисков, которые необходимо обязательно учитывать:
_AccumRgChng не обновится автоматически. Платформа не узнает об удалении записей, из-за чего узлы обмена могут рассинхронизироваться или содержать битые ссылки._Posted в таблице документа). Если пользователь или фоновое задание случайно перепроведет старый документ, движения сформируются повторно, что исказит входящие остатки. У старых документов следует программно снять признак проведения._AccumRgOpt напрямую через SQL могут повредить границы рассчитанных итогов. Управление итогами безопаснее выполнять штатными методами платформы.Массовое удаление строк приводит к сильной фрагментации кластерных и некластерных индексов, а также делает статистику распределения данных неактуальной. В результате оптимизатор запросов SQL начинает строить неоптимальные планы, что приводит к зависаниям и медленной работе отчетов и документов.
После завершения очистки выполним перестроение индексов и обновление статистики для измененных таблиц:
-- Перестроение индексов таблицы регистра
ALTER INDEX ALL ON _AccumRg1234 REBUILD;
-- Полное обновление статистики
UPDATE STATISTICS _AccumRg1234 WITH FULLSCAN;
После выполнения регламентных операций в СУБД вернемся в 1С и запустим пересчет итогов:
РегистрыНакопления.ТоварыНаСкладах.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.ТоварыНаСкладах.ПересчитатьИтоги();
Если мы хотим избежать прямого изменения таблиц в СУБД и сохранить целостность системных механизмов (включая планы обмена), можно использовать оптимизированную очистку средствами платформы. По скорости она приближается к прямым запросам, если предварительно отключить итоги и проверки:
// 1. Отключаем итоги
РегистрыНакопления.ТоварыНаСкладах.УстановитьИспользованиеИтогов(Ложь);
// 2. Очищаем наборы записей регистраторов с отключением проверок
Выборка = Документы.РеализацияТоваровУслуг.Выбрать(, ДатаСреза);
Пока Выборка.Следующий() Цикл
Набор = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Выборка.Ссылка);
Набор.ОбменДанными.Загрузка = Истина; // Отключает подписки и контроль
Набор.Записать(); // Записывает пустой набор (удаляет движения)
КонецЦикла;
// 3. Включаем и пересчитываем итоги
РегистрыНакопления.ТоварыНаСкладах.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.ТоварыНаСкладах.ПересчитатьИтоги();
Использование свойства ОбменДанными.Загрузка = Истина в сочетании с предварительным отключением итогов позволяет безопасно и быстро очистить движения регистра без нарушения целостности базы данных и лицензионных ограничений.