Почему зависает открытие формы списка между «ПриСозданииНаСервере» и «ПриОткрытии» в 1С?

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

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

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

Что происходит между «ПриСозданииНаСервере» и «ПриОткрытии»

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

  1. Формирование схемы компоновки данных: платформа собирает итоговый текст запроса динамического списка с учетом пользовательских настроек (отборов, сортировок, условного оформления и группировок).
  2. Наложение ограничений доступа (RLS): если у пользователя нет полных прав, платформа внедряет в исходный запрос динамического списка условия проверки прав для каждой задействованной таблицы.
  3. Формирование и выполнение SQL-запроса к СУБД: сгенерированный SQL-запрос отправляется в базу данных для выборки первой порции строк, которые должны отобразиться на экране.
  4. Сериализация и передача данных на клиент: сформированная порция данных упаковывается и передается клиентскому приложению для отрисовки интерфейса.

Таким образом, невидимая задержка практически всегда связана с длительным выполнением первого запроса динамического списка на стороне СУБД из-за его сложности или наложения RLS.

Анализ проблем в запросе динамического списка

Посмотрим на пример запроса динамического списка документов, вызывающего сильные задержки при открытии формы:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Заявка.Ссылка,
    Заявка.Номер,
    Заявка.Дата,
    Заявка.СуммаДокумента,
    Заявка.КтоЗаявил.Подразделение КАК ПодразделениеЗаявителя,
    ВЫБОР 
        КОГДА Расшифровка.ДоговорКредитаДепозита <> ЗНАЧЕНИЕ(Справочник.ДоговорыКредитовИДепозитов.ПустаяСсылка)     
            ТОГДА Расшифровка.ДоговорКредитаДепозита.СуммаЛимита * КурсыВалют.Курс
        КОГДА Расшифровка.Заказ ССЫЛКА Справочник.ДоговорыКонтрагентов 
            ТОГДА ВЫРАЗИТЬ(Расшифровка.Заказ КАК Справочник.ДоговорыКонтрагентов).Сумма * КурсыВалют.Курс
        ИНАЧЕ 0.00
    КОНЕЦ КАК СуммаДоговора,
    ЕСТЬNULL(История.РасширенныйСтатусЗаявки, "<нет статуса>") КАК РасширенныйСтатус
ИЗ
    Документ.ЗаявкаНаРасходованиеДенежныхСредств КАК Заявка
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют.СрезПоследних(&ТекущаяДата, ) КАК КурсыВалют
        ПО (Заявка.Валюта = КурсыВалют.Валюта)
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ИсторияСогласованияЗаявокНаРасходованиеДС.СрезПоследних(&ТекущаяДата) КАК История
        ПО Заявка.Ссылка = История.ЗаявкаНаРасходованиеДС
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаявкаНаРасходованиеДенежныхСредств.РасшифровкаПлатежа КАК Расшифровка
        ПО Заявка.Ссылка = Расшифровка.Ссылка И Расшифровка.НомерСтроки = 1

Выясним основные причины деградации производительности в данном запросе:

  1. Разыменование ссылочных полей через точку: конструкция Заявка.КтоЗаявил.Подразделение заставляет платформу строить цепочку неявных левых соединений (LEFT JOIN). Если реквизит имеет составной тип, неявное соединение строится со всеми возможными таблицами типа.
  2. Использование виртуальных таблиц «СрезПоследних» с параметром даты: передача параметра &ТекущаяДата заставляет СУБД сканировать всю физическую таблицу регистра с группировкой и отбором по максимальной дате вместо быстрого чтения из готовой таблицы итогов среза.
  3. Экспоненциальное усложнение под RLS: слово РАЗРЕШЕННЫЕ указывает на проверку прав. Платформа модифицирует итоговый SQL-запрос, внедряя условия RLS отдельно для документа, для табличной части РасшифровкаПлатежа, для регистров сведений и для всех справочников, к которым идет обращение через точку. Итоговый SQL-запрос обрастает десятками подзапросов WHERE EXISTS, ставя СУБД в тупик при выборе плана выполнения.
  4. Соединение с табличной частью документа: соединение с Документ.ЗаявкаНаРасходованиеДенежныхСредств.РасшифровкаПлатежа по номеру строки не позволяет СУБД эффективно использовать индексы и лишает динамический список преимуществ постраничного чтения.

Методы решения и оптимизации

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

1. Упрощение основного запроса динамического списка

Для динамического списка критически важно оставлять запрос максимально простым и плоским. Все расчетные данные, статусы согласования и флаги файлов следует выносить за пределы основного запроса. Обязательно укажем свойство ОсновнаяТаблица (например, Документ.ЗаявкаНаРасходованиеДенежныхСредств) — это позволит платформе включить постраничное чтение данных порциями.

Рассмотрим оптимизированный текст основного запроса:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Заявка.Ссылка КАК Ссылка,
    Заявка.ПометкаУдаления КАК ПометкаУдаления,
    Заявка.Номер КАК Номер,
    Заявка.Дата КАК Дата,
    Заявка.Проведен КАК Проведен,
    Заявка.Организация КАК Организация,
    Заявка.Статус КАК Статус,
    Заявка.СуммаДокумента КАК СуммаДокумента,
    Заявка.Валюта КАК Валюта,
    Заявка.Контрагент КАК Контрагент,
    Заявка.Подразделение КАК Подразделение,
    Заявка.КтоЗаявил КАК КтоЗаявил,
    ЛОЖЬ КАК ЕстьБизнесПроцесс,
    "" КАК НомерКартыЗаявки,
    0 КАК КоличествоОплат
ИЗ
    Документ.ЗаявкаНаРасходованиеДенежныхСредств КАК Заявка

2. Корректное использование обработчика «ПриПолученииДанныхНаСервере»

Все дополнительные расчеты (проверка наличия присоединенных файлов, состояние бизнес-процессов, получение дополнительных реквизитов) перенесем в событие ПриПолученииДанныхНаСервере динамического списка. Этот обработчик вызывается только для тех строк, которые реально отображаются на экране пользователя (обычно 20–50 строк).

Важный момент: чтобы вторичный запрос не замедлялся проверками RLS, обязательно выполним его в привилегированном режиме:


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

3. Настройка итогов для регистров сведений

Если в динамическом списке все же необходимо соединение с регистром сведений через срез последних:

  1. В метаданных регистра сведений установим свойство Разрешить итоги: срез последних.
  2. Уберем передачу параметра даты из виртуальной таблицы в запросе (используем РегистрСведений.КурсыВалют.СрезПоследних без параметров). В этом случае платформа прочитает данные из отдельной системной таблицы итогов без тяжелого сканирования всего регистра.

4. Диагностика узких мест

Если оптимизация структуры запроса не дала мгновенного результата, проанализируем поведение системы с помощью технологического журнала (ТЖ). Для этого настроим сбор событий DBMSSQL / DBPOSTGRS и SDBL с фильтром по длительности выполнения запросов более 1–2 секунд. Это позволит увидеть реальный текст SQL-запроса с развернутыми условиями RLS и точно определить, какое именно соединение блокирует выполнение.

← На главную