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