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