В процессе эксплуатации распределенных информационных баз часто возникает проблема «раздувания» регистров сведений. Когда в системе 45 периферийных узлов, стандартное удаление записей через НаборЗаписей приводит к тому, что 1С регистрирует изменения для каждого узла. В итоге объем передаваемых данных при очередном обмене становится критическим, и система «задыхается». Давайте разберем, как справиться с этой задачей грамотно.
При использовании метода НаборЗаписей.Записать() платформа автоматически создает записи в таблице регистрации изменений плана обмена. Если вы удаляете 12 миллионов записей, для каждого из 45 узлов создается аналогичное количество задач на удаление. Это приводит к блокировкам, росту логов транзакций и зависанию обменов. Чтобы этого избежать, мы должны разделять задачу на два этапа: очистку данных и управление регистрацией изменений.
Вместо того чтобы полагаться на автоматическую регистрацию, мы можем самостоятельно управлять тем, что попадает в обмен. Ключевой объект для работы здесь — ПланыОбмена.УдалитьРегистрациюИзменений(). Этот метод позволяет «вычеркнуть» записи из очереди на передачу в конкретный узел.
Рассмотрим пример кода, который позволяет очистить записи по конкретному сегменту, не перегружая при этом обмен:
Процедура УдалитьТекущийРегистрациюНаСервере(ТекСегмент)
// Создаем набор записей для отбора
Набор = РегистрыСведений.НоменклатураСегмента.СоздатьНаборЗаписей();
Набор.Отбор.Сегмент.Установить(ТекСегмент);
// Цикл для порционного удаления, чтобы не блокировать таблицу
ВсеОбработано = Ложь;
Пока НЕ ВсеОбработано Цикл
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 25000
| ИЗМ.Узел, ИЗМ.Сегмент, ИЗМ.Номенклатура, ИЗМ.Характеристика
|ИЗ РегистрСведений.НоменклатураСегмента.Изменения КАК ИЗМ
|ГДЕ ИЗМ.Сегмент = &Сегмент";
Запрос.Параметры.Вставить("Сегмент", ТекСегмент);
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
ВсеОбработано = Истина;
Продолжить;
КонецЕсли;
Выборка = Результат.Выбрать();
НаборОчистки = РегистрыСведений.НоменклатураСегмента.СоздатьНаборЗаписей();
Пока Выборка.Следующий() Цикл
НаборОчистки.Отбор.Сегмент.Установить(Выборка.Сегмент);
НаборОчистки.Отбор.Номенклатура.Установить(Выборка.Номенклатура);
НаборОчистки.Отбор.Характеристика.Установить(Выборка.Характеристика);
// Удаляем регистрацию для конкретного узла
ПланыОбмена.УдалитьРегистрациюИзменений(Выборка.Узел, НаборОчистки);
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Если записей действительно много (миллионы), никогда не пытайтесь удалить их в одной транзакции. Разбейте процесс на порции по 20-50 тысяч записей. Это позволит:
РегистрСведений.Для этих целей рекомендуется запускать регламентное задание в часы минимальной нагрузки (например, ночью). Если удаление занимает длительное время, не пытайтесь завершить его за одну ночь — растяните процесс на несколько дней.
Проанализируйте, действительно ли данные этого регистра должны передаваться в периферийные узлы:
Перед тем как приступать к массовой чистке, обязательно создайте полную резервную копию. Также помните, что после удаления миллионов записей база данных не уменьшит свой размер автоматически. Вам потребуется выполнить сжатие (Shrink) таблиц в СУБД или провести процедуру тестирования и исправления с реиндексацией, чтобы вернуть производительность системы в норму.
Помните, что регистры сведений — это оперативные данные. Если логика работы скидок на кассах требует наличия записи, убедитесь, что алгоритм расчета сегментов корректно восстанавливает данные после очистки. Не оставляйте «пустоты» там, где бизнес-логика ожидает увидеть результат.