Почему запрос к срезу последних в 1С на PostgreSQL работает медленно у одного пользователя и как это исправить

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

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

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

Выясняем причину: почему PostgreSQL «тормозит» на срезе последних

Основная сложность заключается в том, как платформа 1С транслирует обращение к виртуальной таблице СрезПоследних в SQL-запрос. Когда мы задаем параметр Период, система не просто обращается к таблице итогов (как она делает это без указания периода), а формирует сложную конструкцию с подзапросами или использованием функции MAX(Period) для каждой комбинации измерений. В связке с RLS (Row-Level Security), ограничивающим доступ на уровне записей, итоговый SQL-запрос превращается в «массивное дерево» с множеством соединений.

Разберем, почему проблема может быть локальной (только у одного пользователя):

  1. Проблема «Parameter Sniffing» и кэширование планов: PostgreSQL кэширует планы выполнения. Для пользователя с ограничением прав в отчетах (параметров RLS) СУБД может построить неэффективный план, решив, что вместо сканирования по индексу выгоднее выполнить полное сканирование таблицы (Seq Scan). Это происходит из-за специфического распределения данных, доступных именно этому сотруднику.
  2. Влияние JIT-компиляции: Начиная с версии PostgreSQL 12, включен механизм JIT. При выполнении запросов со сложными условиями RLS СУБД может тратить несколько минут только на компиляцию плана. Если условия прав доступа пользователя делают запрос чуть сложнее, чем у других, срабатывает порог включения JIT, что парализует работу.
  3. Оценка количества строк (Cost Estimation): Если в запросе используется временная таблица, которая связывается со срезом последних, PostgreSQL может ошибочно оценить количество строк в ней (стандартно — 1000 строк). Если реальных строк меньше или условия RLS накладывают дополнительные фильтры, планировщик выбирает метод Nested Loop (вложенные циклы), выполняя тяжелый поиск среза для каждой строки.

Решение 1: Ручное формирование среза последних в тексте запроса

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

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


// Сначала подберем максимальные даты для каждого измерения
ВЫБРАТЬ
    Т.Измерение1,
    Т.Измерение2,
    МАКСИМУМ(Т.Период) КАК Период
ПОМЕСТИТЬ ВТ_МаксДаты
ИЗ
    РегистрСведений.ИмяРегистра КАК Т
ГДЕ
    Т.Период <= &Период
    И Т.Измерение1 В (ВЫБРАТЬ Ссылка ИЗ ВТ_СписокСсылок) // Фильтр из вашей задачи
СГРУППИРОВАТЬ ПО
    Т.Измерение1,
    Т.Измерение2
;

// Теперь получим сами данные, соединившись с основной таблицей регистра
ВЫБРАТЬ
    Т_Данные.*
ИЗ
    ВТ_МаксДаты КАК Даты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ИмяРегистра КАК Т_Данные
    ПО Даты.Измерение1 = Т_Данные.Измерение1
    И Даты.Измерение2 = Т_Данные.Измерение2
    И Даты.Период = Т_Данные.Период

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

Решение 2: Оптимизация работы с временными таблицами

Если вы используете временные таблицы перед соединением со срезом последних (как в примере автора темы), важно «подсказать» СУБД реальный объем данных. В 1С для этого используется метод МенеджерВременныхТаблиц, но на уровне SQL важно, чтобы была выполнена команда ANALYZE.

Рассмотрим рекомендации по работе с временными таблицами в 1С для PostgreSQL:

Решение 3: Настройка параметров PostgreSQL

Если у вас есть доступ к управлению сервером СУБД, проанализируем настройки, которые могут влиять на «тормоза» конкретных пользователей. Проблема часто кроется в механизме GEQO (Genetic Query Optimizer) и JIT.

Посмотрим на важные параметры:

  1. jit = off — попробуйте временно отключить JIT-компиляцию. Если запрос у «проблемного» пользователя сразу ускорится, значит, время уходило на компиляцию сложного SQL-дерева, порожденного RLS.
  2. plan_cache_mode = force_custom_plan — эта настройка заставляет PostgreSQL каждый раз строить план заново, не пытаясь использовать универсальный кэшированный план. Это лечит проблему «отравленного» кэша для конкретных параметров.
  3. from_collapse_limit и join_collapse_limit — увеличение этих значений (например, до 20) может помочь планировщику лучше обрабатывать запросы с большим количеством автоматических соединений от RLS.

Решение 4: Архитектурное разделение регистра

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

Создайте два идентичных регистра:

  1. РегистрОперативный — содержит записи только по активным объектам (например, по незакрытым сделкам или актуальным ценам за последний месяц).
  2. РегистрАрхивный — хранит всю историю.

Большинство транзакционных запросов в документах перенаправьте на РегистрОперативный. Срез последних по нему будет работать мгновенно из-за малого объема данных. Регламентное задание может переносить старые записи из оперативного регистра в архив раз в сутки.

Диагностика через Технологический журнал (ТЖ)

Чтобы окончательно выяснить причину, необходимо проанализировать, какой именно SQL-запрос уходит на сервер для «быстрого» и «медленного» пользователя. Настройте сбор ТЖ с событием DBPOSTGRS. В логах вы увидите текст запроса и, что самое важное, план выполнения (Explain Plan).

Проанализируем план выполнения:

Подводя итог, можно сказать, что связка 1С и PostgreSQL требует более внимательного отношения к написанию запросов, чем MS SQL. Использование виртуальных таблиц с параметрами в условиях RLS — это «зона риска». Лучшей практикой будет либо выполнение таких запросов в привилегированном режиме, либо их ручная декомпозиция на простые составляющие.

← На главную