Почему форма с динамическим списком в 1С открывается медленно, хотя сам запрос выполняется быстро?

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

Часто разработчики 1С сталкиваются с ситуацией, когда форма, содержащая динамический список, открывается недопустимо долго, например, 7-9 секунд. При этом замер производительности показывает, что основное время уходит на выполнение метода Форма.Открыть(), а текст запроса динамического списка, выполненный в консоли, отрабатывает почти мгновенно — поможет инструментарий для отладки и оптимизации решений в 1С. Это вызывает недоумение: если запрос быстрый, то что же так тормозит?

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

Выясняем причину: Консоль запросов vs. Реальная форма

Ключевое заблуждение — считать, что запрос, который выполняется на форме, идентичен тому, что мы тестируем в консоли. На самом деле, платформа проделывает огромную "невидимую" работу, прежде чем отправить финальный запрос в СУБД и отобразить данные пользователю.

Вот что происходит "под капотом":

  1. Дополнительные условия. Платформа добавляет к вашему исходному запросу множество собственных условий: пользовательские отборы, настройки сортировки, установленные группировки, а также служебные поля, необходимые для корректной работы самого списка.
  2. Ограничение доступа на уровне записей (RLS). Если в конфигурации используется RLS, платформа "на лету" модифицирует практически все запросы, добавляя сложные соединения и условия для проверки прав доступа. Это одна из самых частых и неочевидных причин резкого падения производительности — поможет детальный анализ прав доступа и RLS.
  3. Получение "скрытых" данных. Важный момент: даже если вы скрыли колонку в настройках формы (или сняли у нее флаг видимости в конфигураторе), платформа зачастую все равно получает данные для этой колонки. Затраты на получение этих данных есть, хотя на экране их и нет. Именно поэтому полное скрытие элемента управления (Элементы.МойСписок.Видимость = Ложь) дает гораздо больший эффект, чем скрытие отдельных колонок.

В итоге, на сервер СУБД уходит сильно измененный и усложненный запрос, план выполнения которого может кардинально отличаться от плана исходного "чистого" запроса из консоли.

Решение 1. Оптимизация отображения списка

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

Дерево vs. Иерархический список

В свойствах элемента формы "Таблица" для динамического списка есть свойство Отображение. Два самых ресурсоемких варианта — это Дерево и Иерархический список.

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

Решение 2. Оптимизация текста запроса

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

Конструкция ВЫБОР КОГДА

Использование вычисляемых полей прямо в запросе динамического списка — частая причина замедления. Рассмотрим пример:


ВЫБРАТЬ
    ...
    ВЫБОР
        КОГДА ЗадачаЗадачиПользователя.БизнесПроцесс ССЫЛКА БизнесПроцесс.DX_ОбработкаТикета
            ТОГДА ВЫРАЗИТЬ(ЗадачаЗадачиПользователя.БизнесПроцесс КАК БизнесПроцесс.DX_ОбработкаТикета).Контрагент
        КОГДА ЗадачаЗадачиПользователя.БизнесПроцесс ССЫЛКА БизнесПроцесс.DX_Закупка
            ТОГДА "Закупки"
        ИНАЧЕ ИСТИНА
    КОНЕЦ КАК ГруппировочноеПоле
ИЗ
    Задача.ЗадачиПользователя КАК ЗадачаЗадачиПользователя
...

Проблема в том, что СУБД не может эффективно использовать индексы для таких полей. При попытке отсортировать или сгруппировать данные по полю ГруппировочноеПоле, скорее всего, будет происходить полное сканирование таблицы (Full Table Scan), что очень медленно на больших объемах данных.

Решение: Лучшим подходом является предварительный расчет таких данных и сохранение их в отдельный регистр сведений. Тогда в динамическом списке вы будете делать простое соединение с уже готовыми данными, что работает на порядки быстрее.

Коррелирующие подзапросы в условии ГДЕ

Еще одна потенциально медленная конструкция — это подзапрос в условии, который ссылается на поля из основного запроса. Например:


ГДЕ
    (ЗадачаЗадачиПользователя.Исполнитель = &Исполнитель
        ИЛИ ЗадачаЗадачиПользователя.DX_РольИсполнителя В
            (ВЫБРАТЬ
                DX_РегистрАдресацииЗадач.DX_РольИсполнителя
            ИЗ
                РегистрСведений.DX_РегистрАдресацииЗадач КАК DX_РегистрАдресацииЗадач
            ГДЕ
                DX_РегистрАдресацииЗадач.Исполнитель = &Исполнитель
                И DX_РегистрАдресацииЗадач.DX_РольИсполнителя В (&ВыбранныеРоли)))

Фактически, такой подзапрос может выполняться для каждой строки основного запроса. Хотя современные СУБД умеют оптимизировать такие конструкции, они остаются зоной риска. Более производительной альтернативой часто является использование временных таблиц и явных соединений (ЛЕВОЕ СОЕДИНЕНИЕ).

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

Решение 3. "Хитрость" с отложенной отрисовкой

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

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

Разберем по шагам:

  1. Скрываем элемент при создании формы. В модуле формы создаем обработчик события ПриСозданииНаСервере и устанавливаем видимость нашего списка в Ложь.
  2. Отображаем элемент после открытия. Создаем клиентский обработчик события ПриОткрытии и в нем возвращаем видимость списка в Истина.

Посмотрим на пример кода:


// В модуле формы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Скрываем "тяжелый" список при инициализации формы на сервере.
    // Это предотвратит ресурсоемкие операции по получению данных и отрисовке
    // до того, как форма будет показана пользователю.
    Элементы.СписокЗадач.Видимость = Ложь;
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Отображаем список после того, как "каркас" формы уже открылся и доступен пользователю.
    // Загрузка данных начнется в этот момент.
    Элементы.СписокЗадач.Видимость = Истина;
КонецПроцедуры

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

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

← На главную