Почему при массовом изменении артикулов в 1С:УТ 11.5 слетают единицы измерения и растет база?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

Работа с современными конфигурациями на платформе 1С, такими как Управление торговлей 11.5, ERP 2 или Комплексная автоматизация 2, требует от разработчика особого внимания к механизмам записи объектов. Обычный вызов метода Записать(), который корректно работал в старых версиях программ (например, УТ 10.3), в новых реализациях может привести к катастрофическим последствиям: порче данных, потере единиц измерения и взрывному росту объема базы данных SQL.

В этой статье мы подробно проанализируем ситуацию, когда после программного обновления артикулов номенклатуры база выросла в два раза, а единицы хранения (кг, пачки, короба) самопроизвольно изменились на «штуки». Выясним причины этого «коллапса» и разберем правильный алгоритм массового изменения данных.

Анализ исходной проблемы и кода

Рассмотрим типичную ситуацию. Разработчику необходимо программно заполнить поле Артикул для всех позиций номенклатуры, используя код объекта. На первый взгляд, задача тривиальна. Разберем пример кода, который часто используют новички (и который приводит к проблемам):


Процедура Команда1НаСервере()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |   Номенклатура.ЭтоГруппа = ЛОЖЬ
        |   И Номенклатура.Артикул = &пАрт";
    
    Запрос.УстановитьПараметр("пАрт", "");
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        пОбъект = Выборка.Ссылка.ПолучитьОбъект();
        пОбъект.Артикул = "АВТ" + СокрЛП(пОбъект.Код);
        пОбъект.Записать(); // Здесь кроется главная ошибка
    КонецЦикла;
КонецПроцедуры

На первый взгляд, код логичен. Мы выбираем номенклатуру с пустым артикулом, формируем новое значение и записываем объект. Однако при выполнении этого кода в УТ 11.5 начинают происходить необъяснимые вещи. Разберем пошагово, почему это происходит.

Почему слетают единицы измерения (кг на штуки)

В конфигурации 1С:Управление торговлей 11.5 логика работы с единицами измерения (упаковками) значительно усложнена. Проблема «слета» единиц измерения при простой записи объекта связана с работой внутренних обработчиков событий:

  1. Срабатывание бизнес-логики в модуле объекта: При вызове Записать() система запускает процедуры ПередЗаписью и ПриЗаписи. В типовых решениях в эти моменты проверяется целостность структуры данных. Если система обнаруживает изменение ключевых реквизитов или просто выполняет проверку по умолчанию, она может инициировать перезаполнение зависимых параметров.
  2. Механизм единиц для отчетов и хранения: Если в системе включена функциональная опция «Упаковки номенклатуры», но для конкретной позиции они настроены сложным образом, типовой код при программном обращении может не «увидеть» текущие настройки единиц, если они не были явно переданы в структуру объекта. В результате система сбрасывает значение к «дефолтному» — чаще всего это «шт.», так как это первая или основная единица в базовом классификаторе.
  3. Постобработка записи: Как выяснилось в ходе обсуждения проблемы, встроенные постобработчики могут перебирать упаковки и, если текущая единица (например, кг) кажется системе «нелогичной» в контексте измененного объекта, она принудительно перезаписывает её.

Причины двукратного роста размера базы данных

Увеличение размера бэкапа с 6 ГБ до 12 ГБ после простой перезаписи справочника — это не ошибка SQL, а штатное поведение системы при определенных настройках. Выделим три основных фактора роста:

  1. Версионирование объектов: Это основной виновник. В УТ 11 часто включена опция «Версионирование объектов» для справочника Номенклатура. При каждом вызове метода Записать() система создает полную копию данных объекта в регистре сведений ВерсииОбъектов. Номенклатура в УТ 11 — это «тяжелый» объект с десятками реквизитов и табличных частей. Перезаписав 10 000 позиций, вы фактически создаете еще 10 000 их полных копий в базе.
  2. Журнал регистрации: Массовое изменение объектов генерирует огромный поток записей в журнале регистрации. Если база работает в режиме SQL, записи журнала могут существенно раздуть файлы данных или логов транзакций.
  3. Индексация и полнотекстовый поиск: Изменение артикула провоцирует обновление индексов и данных в регистрах, связанных с поиском (например, НоменклатураПоставляемаяПоставщиками). Это вызывает рост LDF-файла (лога транзакций) в SQL Server.

Правильное решение: использование ОбменДанными.Загрузка

Для предотвращения выполнения лишней бизнес-логики, проверок и срабатывания подписок на события при программном изменении данных, критически важно использовать свойство ОбменДанными.Загрузка. Это сообщает системе, что объект записывается в режиме «как есть», и никакие дополнительные проверки или изменения зависимых реквизитов (например, единиц измерения) производиться не должны.

Рассмотрим исправленный и безопасный вариант кода:


Процедура Команда1НаСервереБезопасно()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |   Номенклатура.ЭтоГруппа = ЛОЖЬ";
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        пОбъект = Выборка.Ссылка.ПолучитьОбъект();
        пОбъект.Артикул = "АВТ" + СокрЛП(пОбъект.Код);
        
        // КЛЮЧЕВАЯ СТРОКА: отключение бизнес-логики
        пОбъект.ОбменДанными.Загрузка = Истина; 
        
        пОбъект.Записать();
    КонецЦикла;
КонецПроцедуры

Что дает использование этого флага:

Как минимизировать последствия, если «коллапс» уже случился?

Если вы уже столкнулись с ростом базы и порчей данных, выполните следующие шаги для восстановления:

1. Восстановление единиц измерения

Если данные в регистрах накопления уже «поплыли», простой замены «шт.» на «кг» в справочнике может быть недостаточно. Проанализируйте регистр ШтрихкодыНоменклатуры и УпаковкиНоменклатуры. Возможно, потребуется написать корректирующую обработку, которая сопоставит старые значения единиц (из бэкапа или логов) и вернет их программно с флагом ОбменДанными.Загрузка = Истина.

2. Очистка версий объектов

Чтобы вернуть объем базы к прежним значениям, проанализируйте регистр ВерсииОбъектов. В типовых конфигурациях есть стандартная обработка «Очистка ненужных версий» (раздел Администрирование — Поддержка и обслуживание). Удалите версии, созданные во время выполнения вашей неудачной обработки.

3. Сжатие базы данных (Shrink)

После удаления лишних записей из регистра версий физический размер файла базы данных SQL не уменьшится автоматически. Вам потребуется выполнить процедуру Shrink (сжатие) для базы данных в консоли SQL Server Management Studio, чтобы освободить неиспользуемое место на диске.

4. Очистка журнала регистрации

Если размер базы вырос из-за журнала регистрации, рассмотрите возможность его сокращения. В режиме 1С:Предприятие это делается через «Администрирование — Поддержка и обслуживание — Журнал регистрации — Сократить».

Выводы

Массовая программная обработка справочников в 1С:УТ 11.5 — это ответственная операция. Никогда не используйте метод Записать() «в лоб» без предварительного анализа подписок на события и настройки ОбменДанными.Загрузка. Помните, что современные конфигурации живут по сложным законам объектной модели, где изменение одного реквизита может по цепочке изменить всю структуру данных товара.

← На главную