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

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

В практике разработки на платформе 1С:Предприятие 8.3 часто встречается ситуация, когда одна и та же операция (заполнение документа, формирование отчета) выполняется за считанные секунды под полными правами, но требует нескольких минут при работе обычного пользователя. Рассмотрим эту проблему на примере конфигурации "Учет в управляющих компаниях ЖКХ, ТСЖ и ЖСК 3.0" и выясним, как механизмы безопасности влияют на скорость работы базы данных.

Постановка проблемы и первичная диагностика

Проанализируем типичный случай: документ Зачет авансов (внутреннее имя УПЖКХ_ЗакрытиеПериодаПоНачислениямЖКХ) под администратором заполняется за 2–5 секунд, а под пользователем — более 2 минут. При этом проведение документа в обоих случаях занимает одинаковое время. Это сразу наводит на мысль, что проблема кроется в алгоритме выборки данных, а не в записи движений.

Для выявления "узкого места" воспользуемся встроенным инструментом Замер производительности. В результате замера мы увидим, что основное время (около 220 секунд) поглощается одной строкой кода:

Результат = Запрос.Выполнить().Выгрузить();

Это классический признак того, что проблема находится на уровне СУБД (или движка файловой базы), и она напрямую связана с тем, как платформа трансформирует запрос 1С в SQL-запрос с учетом прав доступа.

Влияние механизма RLS (Record Level Security)

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

Выясним причину, изучив настройки ролей для регистра накопления УПЖКХ_Начисления. Если у роли пользователя в колонке "Чтение" стоит условие, платформа автоматически добавляет это условие в каждый запрос, где используется данный регистр. Проанализируем типичный шаблон ограничения, используемый в решениях для ЖКХ:

#ПоОбъектамУчета("ЛицевойСчет.Адрес.Владелец","")

Этот шаблон заставляет систему при каждой попытке прочитать запись из регистра проверять права доступа к лицевому счету, затем к адресу этого счета и, наконец, к владельцу (зданию или контрагенту). На уровне базы данных это превращается в огромное количество неявных соединений (LEFT JOIN).

Почему обращение "через точку" замедляет запрос

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


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    ЕСТЬNULL(УПЖКХ_Начисления.СуммаНачисления, 0) КАК Перерасчет,
    втТаблицаОстатков.Объект КАК Объект,
    втТаблицаОстатков.Услуга КАК Услуга
ПОМЕСТИТЬ втПерерасчетПредварительная
ИЗ
    втТаблицаОстатков КАК втТаблицаОстатков
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.УПЖКХ_Начисления КАК УПЖКХ_Начисления
    ПО втТаблицаОстатков.Объект = УПЖКХ_Начисления.ЛицевойСчет
    И втТаблицаОстатков.Услуга = УПЖКХ_Начисления.Услуга
ГДЕ
    УПЖКХ_Начисления.Организация = &Организация
    И УПЖКХ_Начисления.СуммаНачисления < 0

Под администратором этот запрос выполняется "как есть". Однако под пользователем с RLS платформа видит обращение к РегистрНакопления.УПЖКХ_Начисления и "на лету" достраивает запрос. Если в шаблоне прав указано ЛицевойСчет.Адрес.Владелец, то к каждой записи регистра пристыковываются таблицы справочников ЛицевыеСчета, ЖилыеЗдания и другие. В файловом режиме (база 6 Гб+) оптимизатор не справляется с такой вложенностью, и время выполнения растет экспоненциально.

Важный нюанс: наличие ключевого слова РАЗРЕШЕННЫЕ лишь предотвращает ошибку доступа, но не отменяет сам механизм проверки прав. Если убрать РАЗРЕШЕННЫЕ, запрос под пользователем просто выдаст ошибку "Нарушение прав доступа", если он затронет хотя бы одну "чужую" запись.

Вариант оптимизации запроса

Чтобы ускорить выполнение, мы можем переписать запрос таким образом, чтобы минимизировать влияние RLS. Один из способов — сначала выбрать нужные данные из регистра во временную таблицу, проиндексировать их, а уже потом соединять с остальными данными. Посмотрим на пример оптимизированного кода:


// Шаг 1: Выбираем только необходимые данные из регистра с учетом фильтров
ВЫБРАТЬ РАЗРЕШЕННЫЕ
    УПЖКХ_Начисления.ЛицевойСчет,
    УПЖКХ_Начисления.Договор,
    УПЖКХ_Начисления.Услуга,
    УПЖКХ_Начисления.СуммаНачисления
ПОМЕСТИТЬ ТабРН_Начисления
ИЗ
    РегистрНакопления.УПЖКХ_Начисления КАК УПЖКХ_Начисления
ГДЕ
    УПЖКХ_Начисления.Организация = &Организация
    И УПЖКХ_Начисления.СуммаНачисления < 0
ИНДЕКСИРОВАТЬ ПО
    ЛицевойСчет,
    Услуга;

// Шаг 2: Соединяем подготовленную временную таблицу
ВЫБРАТЬ
    ЕСТЬNULL(ТабРН_Начисления.СуммаНачисления, 0) КАК Перерасчет,
    втТаблицаОстатков.Объект КАК Объект
ИЗ
    втТаблицаОстатков КАК втТаблицаОстатков
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТабРН_Начисления КАК ТабРН_Начисления
    ПО втТаблицаОстатков.Объект = ТабРН_Начисления.ЛицевойСчет
    И втТаблицаОстатков.Услуга = ТабРН_Начисления.Услуга;

Такой подход позволяет системе один раз применить RLS при заполнении ТабРН_Начисления. Дальнейшие соединения будут происходить уже с временной таблицей в памяти, которая не обременена ограничениями прав доступа.

Рекомендуемые способы решения

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

  1. Использование привилегированного режима: Это самый эффективный метод. Если бизнес-логика позволяет выполнять заполнение документа без проверки прав конкретного пользователя (например, алгоритм заполнения жестко определен программно), код выборки данных следует обернуть в команду УстановитьПривилегированныйРежим(Истина). В этом случае RLS игнорируется, и скорость будет как у администратора.
  2. Оптимизация RLS-шаблонов: Рассмотрим возможность упрощения пути проверки прав. Вместо цепочки ЛицевойСчет.Адрес.Владелец лучше использовать прямое ограничение по реквизиту, если это возможно. Также стоит убедиться, что поля, участвующие в RLS (например, ЛицевойСчет), проиндексированы в регистре.
  3. Переход на клиент-серверный вариант: СУБД (MS SQL, PostgreSQL) гораздо лучше справляются со сложными запросами, которые генерирует RLS, чем файловый движок. Для баз объемом более 6 Гб переход на SQL-версию часто является необходимым условием стабильной работы.
  4. Использование расширений: Если конфигурация типовая и находится на поддержке, можно создать расширение, в котором перехватить процедуру заполнения и выполнить её в привилегированном режиме или с оптимизированным запросом.

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

← На главную