Как правильно очистить регистр накопления средствами SQL при свертке базы 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При свертке крупных информационных баз 1С стандартная процедура удаления движений документов штатными методами может занимать дни или даже недели. В связи с этим часто возникает задача ускорить процесс и очистить устаревшие записи регистров накопления напрямую через СУБД (SQL). Разберем, как устроен этот процесс, какие шаги необходимо выполнить, с какими скрытыми рисками можно столкнуться и как правильно обслужить базу данных после прямой модификации таблиц.

Порядок очистки регистра накопления через SQL

Если требуется очистить таблицу регистра не полностью, а только за определенный период (например, отрезать прошлые годы, предварительно сформировав документы ввода начальных остатков на дату среза), команда TRUNCATE TABLE не подойдет, так как она полностью стирает содержимое таблицы. В этом случае применяется инструкция DELETE. Рассмотрим пошаговый алгоритм действий:

  1. Формирование остатков: создаем и проводим документы ввода начальных остатков на дату свертки базы штатными средствами 1С.
  2. Определение имен таблиц: с помощью метода ПолучитьСтруктуруХраненияБазыДанных() в 1С определяем физические имена таблиц регистра движений и таблицы итогов в SQL.
  3. Отключение расчета итогов: перед удалением данных отключаем использование итогов регистра накопления средствами 1С, чтобы исключить лишнюю нагрузку и блокировки.
  4. Удаление устаревших записей: выполняем удаление строк из основной таблицы движений регистра по условию периода.
  5. Очистка и пересчет итогов: очищаем или пересчитываем таблицы итогов, после чего включаем использование итогов обратно.
  6. Обслуживание СУБД: перестраиваем индексы и обновляем статистику базы данных.

Посмотрим на пример получения имени таблицы в 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С влечет за собой несколько критических рисков, которые необходимо обязательно учитывать:

  1. Планы обмена и регистрация изменений: если регистр накопления входит в состав планов обмена (РИБ или синхронизация данных), таблица изменений _AccumRgChng не обновится автоматически. Платформа не узнает об удалении записей, из-за чего узлы обмена могут рассинхронизироваться или содержать битые ссылки.
  2. Флаг проведения документов-регистраторов: удаление движений из таблицы регистра не меняет статус проведения самих документов (поле _Posted в таблице документа). Если пользователь или фоновое задание случайно перепроведет старый документ, движения сформируются повторно, что исказит входящие остатки. У старых документов следует программно снять признак проведения.
  3. Кэш сервера 1С: кластер серверов 1С кэширует структуру данных и состояние итогов. После любых манипуляций на уровне СУБД рекомендуется перезапустить службу сервера 1С:Предприятия.
  4. Таблицы настроек итогов: манипуляции с таблицей _AccumRgOpt напрямую через SQL могут повредить границы рассчитанных итогов. Управление итогами безопаснее выполнять штатными методами платформы.

Обязательное обслуживание индексов и статистики

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

После завершения очистки выполним перестроение индексов и обновление статистики для измененных таблиц:


-- Перестроение индексов таблицы регистра
ALTER INDEX ALL ON _AccumRg1234 REBUILD;

-- Полное обновление статистики
UPDATE STATISTICS _AccumRg1234 WITH FULLSCAN;

После выполнения регламентных операций в СУБД вернемся в 1С и запустим пересчет итогов:


РегистрыНакопления.ТоварыНаСкладах.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.ТоварыНаСкладах.ПересчитатьИтоги();

Штатная альтернатива: быстрая очистка через платформу 1С

Если мы хотим избежать прямого изменения таблиц в СУБД и сохранить целостность системных механизмов (включая планы обмена), можно использовать оптимизированную очистку средствами платформы. По скорости она приближается к прямым запросам, если предварительно отключить итоги и проверки:


// 1. Отключаем итоги
РегистрыНакопления.ТоварыНаСкладах.УстановитьИспользованиеИтогов(Ложь);

// 2. Очищаем наборы записей регистраторов с отключением проверок
Выборка = Документы.РеализацияТоваровУслуг.Выбрать(, ДатаСреза);
Пока Выборка.Следующий() Цикл
    Набор = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
    Набор.Отбор.Регистратор.Установить(Выборка.Ссылка);
    Набор.ОбменДанными.Загрузка = Истина; // Отключает подписки и контроль
    Набор.Записать(); // Записывает пустой набор (удаляет движения)
КонецЦикла;

// 3. Включаем и пересчитываем итоги
РегистрыНакопления.ТоварыНаСкладах.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.ТоварыНаСкладах.ПересчитатьИтоги();

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

← На главную