Как правильно преобразовать реквизит регистра накопления в измерение без потери данных

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

В процессе развития информационной системы на базе 1С нередко возникает ситуация, когда данных в реквизитах регистра накопления становится недостаточно для эффективного построения отчетов или анализа. Например, когда требуется использовать поле как фильтр в параметрах виртуальных таблиц (Остатки, Обороты). Единственный способ реализовать это эффективно — превратить реквизит в измерение. Рассмотрим детально, как выполнить эту операцию, сохранив все накопленные данные и не нарушив работу системы.

Анализ проблемы и выбор стратегии

Прежде всего, разберем, почему нельзя просто изменить категорию объекта в конфигураторе. Если вы удалите реквизит и создадите измерение с тем же именем, при обновлении конфигурации базы данных 1С физически удалит колонку из таблицы SQL и создаст новую, пустую. Все исторические данные будут безвозвратно потеряны. Поэтому нам необходимо применить стратегию "мягкого обновления".

Выясним, какой из двух подходов нам подходит больше:

  1. Полное перепроведение документов. Этот способ кажется простым: изменили структуру и заставили систему заново сформировать движения. Однако, как справедливо отмечено в обсуждении, это "фантастика" для зрелых баз. Наличие ручных корректировок, записей документов ОперацияБух или КорректировкаЗаписейРегистров, а также изменение логики проведения в прошлых периодах сделает результат непредсказуемым.
  2. Программный перенос данных. Это наиболее безопасный метод. Мы создаем новое измерение, переносим в него значения из старого реквизита программным кодом и только после проверки целостности данных избавляемся от старого поля.

Шаг 1. Подготовка метаданных в конфигураторе

Проанализируем последовательность действий в конфигураторе. Чтобы не запутаться и соблюсти стандарты разработки (особенно если используется БСП), выполним следующие действия:

  1. Найдем целевой реквизит в регистре накопления. Переименуем его, добавив префикс Удалить (например, УдалитьСклад). В синониме укажем в скобках (не используется). Это даст понять другим разработчикам и пользователям, что поле готовится к выводу из эксплуатации.
  2. Создадим новое измерение с тем же именем, которое раньше было у реквизита (например, Склад). Настроим его тип и свойства (индексирование, запрет пустых значений и т.д.) в соответствии с требованиями.
  3. Если регистр является остаточным, крайне важно убедиться, что новое измерение будет заполняться во всех документах-регистраторах, иначе возникнет "расползание" остатков: приход будет зафиксирован без измерения, а расход — с измерением.

Шаг 2. Программный перенос данных

Теперь рассмотрим, как перенести данные из УдалитьСклад в Склад. Самый эффективный способ — работа с наборами записей. Разберем пример кода, который выполняет эту задачу порционно по каждому регистратору.


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

Важный момент: использование ОбменДанными.Загрузка = Истина позволяет существенно ускорить процесс записи, так как система не будет запускать обработчики событий (ПередЗаписью, ПриЗаписи) и выполнять автоматические проверки итогов для каждой записи.

Шаг 3. Использование механизмов БСП для обновления

В типовых конфигурациях для таких задач предусмотрена подсистема "Обновление информационной базы". Вместо запуска разовой обработки вручную, правильнее будет зарегистрировать обработчик обновления. Это позволит выполнить перенос данных в фоновом режиме (отложенное обновление), не прерывая работу пользователей.

Разберем, как это работает. В модуле управления обновлением вы регистрируете процедуру. Система сама отследит, какие данные уже обработаны, и выведет прогресс в консоль администратора. Это критически важно для баз объемом в сотни гигабайт, где реструктуризация таблицы регистра может занять часы.

Особенности работы на уровне СУБД

Посмотрим на ситуацию с точки зрения SQL-сервера. Измерения регистра всегда входят в кластерный индекс. Добавление нового измерения заставляет сервер перестраивать всю таблицу. Проанализируем риски:

Альтернативный вариант: Индексирование

Выясним, всегда ли нужно делать реквизит измерением. Если ваша единственная цель — ускорить поиск в запросах типа:


ВЫБРАТЬ * ИЗ РегистрНакопления.МойРегистр ГДЕ Склад = &Параметр

...то достаточно просто установить свойство "Индексировать" у реквизита. Это создаст индекс в базе данных и ускорит выборку. Однако, если вы хотите использовать Склад в параметрах виртуальной таблицы:


РегистрыНакопления.МойРегистр.Обороты(,, , Склад = &Параметр)

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

Заключение

Подводя итог, краткий чек-лист для безопасного обновления:

  1. Переименовываем реквизит в Удалить....
  2. Создаем новое измерение.
  3. Пишем обработку переноса данных с использованием НаборЗаписей и ОбменДанными.Загрузка.
  4. Обновляем код проведения документов, чтобы новые движения сразу формировались с заполненным измерением.
  5. После успешного переноса и проверки отчетов (желательно через один релиз) окончательно удаляем ненужный реквизит из метаданных.

Такой подход минимизирует риски потери данных и гарантирует стабильную работу системы даже на высоконагруженных внедрениях.

← На главную