Почему тормозит динамический список в 1С на PostgreSQL при установке отборов и как это исправить?

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

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

Анализ причин медленной работы

Проанализируем механику работы динамического списка и СУБД PostgreSQL. Основные факторы, приводящие к резкому падению производительности:

  1. Отборы по вычисляемым полям. Если в запросе динамического списка присутствуют конструкции вида РАЗНОСТЬДАТ(Контрагенты.ДатаРождения, &ТекущаяДата, ГОД) и на поле накладывается отбор компоновки данных, СУБД не может применить индекс. Чтобы вычислить возраст для каждой записи, PostgreSQL вынужден выполнять полное последовательное сканирование таблицы (Seq Scan), производя расчет функции над каждой строкой.
  2. Использование конструкции ВЫБРАТЬ РАЗЛИЧНЫЕ. Ключевое слово DISTINCT блокирует постраничную выборку порциями (курсором). Платформа 1С в таком случае считывает всю выборку целиком и выполняет сортировку во временных файлах на диске.
  3. Отсутствие основной таблицы. Если в свойствах динамического списка не указана «Основная таблица», платформа не может корректно транслировать отборы в предложение WHERE по первичному ключу, формируя сложные вложенные подзапросы.
  4. Отсутствие индекса по полю отбора. В отличие от стандартных реквизитов (Ссылка, Код), дополнительные реквизиты объектов по умолчанию не индексируются.
  5. Неактуальная статистика базы данных. После переноса информационной базы планировщик PostgreSQL не располагает точной информацией о распределении данных и выбирает неоптимальный план выполнения запроса.

Способ 1. Замена вычисляемых отборов на фильтрацию по индексированным полям

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

Рассмотрим пример кода на сервере, в котором мы рассчитываем пороговую дату и передаем ее в параметр запроса динамического списка:


&НаСервере
Процедура УстановитьОтборПоВозрастуНаСервере(ОтборВозрастДо)
    
    // Рассчитываем пороговую дату в коде 1С
    Если ОтборВозрастДо > 0 Тогда
        ПороговаяДата = ДобавитьМесяц(ТекущаяДатаСеанса(), -ОтборВозрастДо * 12);
        
        // Устанавливаем условие непосредственно на реквизит даты
        Список.Параметры.УстановитьЗначениеПараметра("ТекДатаМинусГоды", ПороговаяДата);
        Список.Параметры.УстановитьЗначениеПараметра("ПрименятьОтборПоВозрасту", Истина);
    Иначе
        Список.Параметры.УстановитьЗначениеПараметра("ТекДатаМинусГоды", Дата(1, 1, 1));
        Список.Параметры.УстановитьЗначениеПараметра("ПрименятьОтборПоВозрасту", Ложь);
    КонецЕсли;
    
КонецПроцедуры

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


ВЫБРАТЬ
    Контрагенты.Ссылка КАК Ссылка,
    Контрагенты.Наименование КАК Наименование,
    Контрагенты.ДатаРожденияКлиента КАК ДатаРожденияКлиента,
    Контрагенты.Менеджер КАК Менеджер
ИЗ
    Справочник.Контрагенты КАК Контрагенты
ГДЕ
    НЕ Контрагенты.ЭтоГруппа
    И (&ПрименятьОтборПоВозрасту = ЛОЖЬ ИЛИ Контрагенты.ДатаРожденияКлиента >= &ТекДатаМинусГоды)

Посмотрим на результат: PostgreSQL выполняет прямое сравнение значений даты с константой, что позволяет планировщику СУБД задействовать индекс по полю ДатаРожденияКлиента.

Способ 2. Оптимизация структуры динамического списка

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

  1. Укажите «Основную таблицу». В свойствах динамического списка в поле «Основная таблица» всегда выбирайте соответствующий объект метаданных (например, Справочник.Контрагенты). Это позволяет платформе оптимизировать построение условий и использовать выборку по первичному ключу.
  2. Удалите ВЫБРАТЬ РАЗЛИЧНЫЕ. Если в результате объединения таблиц появляются дубли, перепишите запрос так, чтобы избавиться от размножения строк без использования DISTINCT.
  3. Включите индексацию реквизита. В дереве метаданных конфигуратора откройте свойства реквизита ДатаРожденияКлиента и установите свойство Индексировать в значение Индексировать или Индексировать с доп. упорядочиванием.

Способ 3. Динамическое управление текстом запроса

Если условий отбора много, можно формировать текст запроса динамически, чтобы не перегружать СУБД лишними проверками параметров через ИЛИ. Рассмотрим реализацию динамической подстановки условий:


&НаСервере
Процедура ОбновитьЗапросДинамическогоСписка()
    
    БазовыйТекст = 
        "ВЫБРАТЬ
        |   Контрагенты.Ссылка КАК Ссылка,
        |   Контрагенты.Наименование КАК Наименование,
        |   Контрагенты.ДатаРожденияКлиента КАК ДатаРожденияКлиента
        |ИЗ
        |   Справочник.Контрагенты КАК Контрагенты
        |ГДЕ
        |   НЕ Контрагенты.ЭтоГруппа";
    
    Если ЗначениеЗаполнено(ОтборВозрастДо) И ОтборВозрастДо > 0 Тогда
        ПороговаяДата = ДобавитьМесяц(ТекущаяДатаСеанса(), -ОтборВозрастДо * 12);
        БазовыйТекст = БазовыйТекст + " И Контрагенты.ДатаРожденияКлиента >= &ПороговаяДата";
        Список.ТекстЗапроса = БазовыйТекст;
        Список.Параметры.УстановитьЗначениеПараметра("ПороговаяДата", ПороговаяДата);
    Иначе
        Список.ТекстЗапроса = БазовыйТекст;
    КонецЕсли;
    
КонецПроцедуры

Способ 4. Обновление статистики и тюнинг PostgreSQL

Проанализируем состояние самой СУБД. При миграции базы данных или массовой загрузке данных планировщик PostgreSQL может не иметь актуальной статистики распределения значений в таблицах.

  1. Сбор статистики. Выполните регламентную операцию анализа базы данных в PostgreSQL: VACUUM ANALYZE; Убедитесь, что параметр autovacuum в postgresql.conf включен (autovacuum = on).
  2. Корректировка стоимости чтения страниц. Для серверов с быстрыми SSD/NVMe-дисками стандартное значение random_page_cost = 4.0 завышено, из-за чего планировщик игнорирует индексы. Установите в postgresql.conf: random_page_cost = 1.1
  3. Настройка collapse limit. Для корректной оптимизации подзапросов, генерируемых платформой 1С, рекомендуется увеличить лимиты объединения:
    
    from_collapse_limit = 20
    join_collapse_limit = 20
    

Сочетание правильного построения запросов, индексации реквизитов и актуализации статистики PostgreSQL позволяет сократить время отклика динамического списка с нескольких минут до долей секунды.

← На главную