Как лучше получать отдельный столбец значений реквизита в 1С

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

В практике разработки на платформе 1С:Предприятие 8 часто возникает задача получения списка всех значений определенного реквизита для всех элементов справочника или документов. Например, нам может понадобиться массив всех артикулов, кодов или специфических признаков объектов для дальнейшей обработки. Рассмотрим подробнее, как сделать это максимально эффективно, правильно работая с метаданными и оптимизируя нагрузку на систему.

Динамическое получение имени объекта метаданных

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

Самый надежный и распространенный способ — использование пустой ссылки объекта. Рассмотрим пример кода, который можно разместить в модуле менеджера:


Функция ПолучитьВсеКоды() Экспорт
    // Получаем полное имя объекта метаданных динамически
    ПолноеИмяОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(ЭтотОбъект.ПустаяСсылка())).ПолноеИмя;
    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Код ИЗ " + ПолноеИмяОбъекта;
    
    Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Код");
КонецФункции

Выясним причину использования конструкции ЭтотОбъект.ПустаяСсылка(). В модуле менеджера ЭтотОбъект ссылается на сам менеджер справочника. У менеджера есть метод ПустаяСсылка(), который возвращает пустую ссылку данного типа. Далее, через ТипЗнч() и поиск в глобальной коллекции Метаданные, мы получаем объект описания метаданных и его свойство ПолноеИмя (например, "Справочник.Товары").

Оптимизация получения данных: ВыгрузитьКолонку vs Выборка

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

Важный момент: метод Выгрузить() сначала создает в оперативной памяти сервера полную таблицу значений (ТЗ), копируя туда все данные из результата запроса. Если в справочнике 500 000 записей, создание такой таблицы может вызвать резкий скачок потребления RAM. Рассмотрим альтернативный, более экономный способ через обход выборки:


РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
МассивЗначений = Новый Массив;

Пока Выборка.Следующий() Цикл
    МассивЗначений.Добавить(Выборка.Код);
КонецЦикла;

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

Индексация реквизитов для ускорения запроса

Посмотрим на ситуацию с точки зрения базы данных (SQL). Если мы часто выбираем данные по конкретному реквизиту или накладываем на него условия, крайне важно проверить настройки этого реквизита в конфигураторе. Для стандартных полей, таких как Код или Наименование, индексы обычно создаются автоматически. Но если вы работаете с произвольным реквизитом, выполните следующие шаги:

  1. Откройте свойства нужного реквизита в конфигураторе.
  2. Найдите свойство Индексировать.
  3. Установите значение Индексировать или Индексировать с доп. упорядочиванием.

Без индекса СУБД будет вынуждена выполнять полное сканирование таблицы (Full Table Scan), что значительно замедлит работу системы при росте количества записей.

Получение только уникальных значений

Если наша задача — получить список всех уникальных категорий или групп, которые встречаются у элементов, нам не нужно выгружать все дубликаты и потом очищать их в 1С. Разберем, как переложить эту задачу на SQL-сервер с помощью ключевого слова РАЗЛИЧНЫЕ:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |   Товары.Категория КАК Категория
    |ИЗ
    |   Справочник.Товары КАК Товары";

СписокКатегорий = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Категория");

Это решение гораздо эффективнее, так как объем данных, передаваемых от сервера базы данных к серверу приложений 1С, сокращается в десятки раз.

Учет прав доступа и RLS

Проанализируем еще один важный аспект — права доступа. По умолчанию запрос в 1С выполняется с учетом ограничений доступа на уровне записей (RLS). Если у текущего пользователя нет прав на чтение части элементов справочника, они просто не попадут в итоговый массив.

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


УстановитьПривилегированныйРежим(Истина);
// Выполняем запрос, теперь RLS не ограничивает выборку
Результат = Запрос.Выполнить();
УстановитьПривилегированныйРежим(Ложь);

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

Выясним, есть ли отличия, если реквизит имеет тип Строка неограниченной длины. Да, отличия существенные. На уровне SQL-запроса к таким полям нельзя применять группировки или оператор РАЗЛИЧНЫЕ. Если вам нужно получить уникальные значения по такому полю, вам придется сначала выбрать все данные в таблицу значений, а затем использовать метод ТЗ.Свернуть("ИмяКолонки").

Подведем итог. Для получения "столбца" значений лучше всего использовать Запрос. Для универсальности в модуле менеджера используйте поиск метаданных по типу пустой ссылки. При больших объемах данных отдавайте предпочтение обходу выборки, а не методу Выгрузить(), и всегда помните об индексации реквизитов и правах доступа RLS.

← На главную