Почему в динамическом списке 1С пропадают поля запроса и как это исправить?

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

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

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


ВЫБРАТЬ
    ВТ.Организация КАК Организация,
    ВТ.Номенклатура КАК Номенклатура,
    ВТ.Характеристика КАК Характеристика,
    ВТ.Склад КАК Склад,
    ВТ.Количество КАК Количество,
    ВТ.Резерв КАК Резерв    
ПОМЕСТИТЬ ВТ_ОстаткиПредв

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

Выясним причину. Это поведение не является ошибкой платформы 1С. Мы имеем дело со штатным механизмом оптимизации Системы Компоновки Данных (СКД). Так как динамические списки работают на базе СКД, встроенный оптимизатор анализирует итоговые настройки списка. Если он видит, что какие-то поля не выводятся на форму пользователю и не участвуют в отборах, он физически "вырезает" их из текста SQL-запроса для ускорения выборки данных. К сожалению, оптимизатор не всегда идеально оценивает влияние удаленного поля на группировку строк. Рассмотрим несколько способов, как мы можем управлять этим процессом и заставить СКД работать так, как нам нужно.

Способ 1: Свойство поля "Использовать всегда"

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

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

Это заставит систему всегда включать данное поле в выборку. Однако проанализируем побочные эффекты этого метода:

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

Во-вторых, могут возникнуть программные ошибки при работе с ТекущиеДанные. Если пользователь настроит в списке свою собственную группировку, то при выделении строки-группировки обращение к таким полям может вернуть Неопределено или вызвать ошибку, так как для строки-группировки детального поля физически не существует. Это обязательно нужно учитывать при написании обработчиков событий формы.

Способ 2: Синтаксис обязательных полей в расширениях СКД

Разберем более архитектурно правильный метод. Мы можем дать явную команду оптимизатору на уровне самого текста запроса. Чтобы система не удаляла поле при формировании временной таблицы, используем расширения языка запросов СКД со знаком звездочки.

Непосредственно в запросе временной таблицы нам нужно прописать поля внутри фигурных скобок:


{ВЫБРАТЬ 
    Организация.*,
    Склад.*
}

Этот синтаксис жестко сигнализирует платформе, что указанные поля должны присутствовать в выборке независимо от итоговых настроек видимости списка у пользователя.

Способ 3: Отключение "Автозаполнения"

Рассмотрим радикальный способ. Если запрос очень сложный и оптимизатор СКД ломает логику в нескольких местах, мы можем полностью отключить автоматическое формирование полей.

Для этого в свойствах динамического списка нужно снять флажок Автозаполнение. В этом случае система прекратит вмешиваться в структуру выборки. Однако нам придется вручную, используя язык расширений СКД, прописать все необходимые доступные поля, отборы и параметры, которые пользователь сможет использовать в настройках.

Способ 4: Фиктивные отборы и использование функций

Посмотрим на практические трюки, к которым часто прибегают разработчики. Суть метода заключается в том, чтобы запутать оптимизатор или создать для него искусственную зависимость.

Мы можем добавить в последний запрос нейтральное выражение отбора с обращением к проблемному полю. Например:

ГДЕ НЕ ВТ.Склад ЕСТЬ NULL

Второй вариант этого трюка — обернуть проблемное поле в функцию непосредственно в блоке выбора:


ВЫБРАТЬ
    ЕСТЬNULL(ВТ.Склад, ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)) КАК Склад

Или использовать приведение типов:


ВЫБРАТЬ
    ВЫРАЗИТЬ(ВТ.Склад КАК Справочник.Склады) КАК Склад

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

Способ 5: Назначение полей "Измерениями" в СКД

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

Указание роли Измерение для таких полей, как Склад или Характеристика, сообщает системе компоновки, что удалять данное поле нельзя ни при каких обстоятельствах. Оно отвечает за правильный разрез итогов, и его исключение приведет к математически неверным остаткам. Система это понимает и сохраняет поле в итоговом SQL-запросе.

Применяя эти методы, мы сможем полностью контролировать формирование запросов в динамических списках и избегать проблем с исчезающими данными и некорректными остатками на формах платформы 1С.

← На главную