Проблема производительности отчетов при включенном ограничении прав доступа на уровне записей (RLS) — одна из самых частых и сложных в диагностике. Ситуация, когда под полными правами отчет строится за минуты, а у пользователя висит часами, требует глубокого понимания взаимодействия платформы 1С и СУБД. В данной статье мы подробно разберем реальный кейс, проанализируем причины замедления и рассмотрим методы решения.
Рассмотрим типичную ситуацию. У нас есть тяжелый отчет на большом объеме данных. Показатели производительности следующие:
Ключевой момент здесь — разница между временем выполнения SQL-запроса и временем выдачи результата пользователю. Если SQL отработал за 6 минут, а пользователь ждет еще 2 часа, значит, проблема находится на стороне сервера приложений 1С в процессе пост-обработки данных.
Одна из самых неочевидных причин "тормозов" после выполнения запроса — это механизм получения представлений объектов.
Когда система компоновки данных (СКД) или обычный код выводит результат, содержащий ссылочные поля (например, СправочникСсылка.Организации), платформе нужно отобразить пользователю не уникальный идентификатор (GUID), а понятное наименование.
Как это работает под полными правами:
Платформа просто делает запрос к таблице справочника и получает поле Наименование. Это происходит массово и быстро.
Как это работает под RLS:
Прежде чем показать пользователю строку "ООО Ромашка", система обязана проверить: а имеет ли право этот пользователь вообще знать о существовании "ООО Ромашка"?
Если в выборку попало 100 000 строк с разными ссылками, платформа может начать выполнять проверку прав доступа для каждой ссылки отдельно. Это может порождать тысячи микро-запросов к БД или сложные вычисления на сервере приложений, что и вызывает задержку в несколько часов после завершения основного запроса.
Решение:
ВЫБРАТЬ Организация.Наименование ....ВЫБРАТЬ РАЗРЕШЕННЫЕ, чтобы отсечь недоступные данные на этапе выборки, а не вывода.В ходе анализа рассматриваемой ситуации выяснилась критическая деталь. Ограничение RLS (шаблон доступа) накладывало условие фильтрации на поле, которое в регистре являлось не Измерением, а Ресурсом или обычным Реквизитом.
Почему это важно:
Механизм RLS физически добавляет к вашему запросу конструкцию WHERE (ГДЕ). Запрос превращается из:
ВЫБРАТЬ * ИЗ Регистр
в:
ВЫБРАТЬ * ИЗ Регистр
ГДЕ Регистр.Организация В (ВЫБРАТЬ Разрешенные...)
Если поле Организация не проиндексировано (а ресурсы регистров обычно не индексируются по умолчанию), СУБД не может быстро найти нужные записи. Ей приходится выполнять Full Table Scan (полное сканирование таблицы) для каждой проверки прав. На больших объемах данных это катастрофически снижает производительность.
Решение:
Проверьте поля, участвующие в шаблонах RLS. Если они используются в условиях соединения или фильтрации, обязательно включите для них свойство "Индексировать" в конфигураторе.
Давайте посмотрим на структуру шаблонов RLS. Часто встречается конструкция:
ГДЕ Реквизит1 = &Параметр1
ИЛИ Реквизит2 = &Параметр2
Конструкция ИЛИ (OR) крайне тяжела для оптимизатора запросов (особенно в PostgreSQL). Она часто приводит к отказу от использования индексов. Если RLS добавляет такие условия к каждой таблице в запросе, время выполнения растет экспоненциально.
Решение:
Старайтесь избегать ИЛИ в RLS. Если возможно, разбивайте права на разные роли или используйте регистры соответствия ключей доступа (как это реализовано в БСП — Библиотеке Стандартных Подсистем), где все доступные объекты хранятся в одной плоской таблице.
Иногда, чтобы ускорить отчет, разработчики решают выполнять его в Привилегированном режиме, передавая ограничения доступа вручную через параметры запроса. Рассмотрим, с какой ошибкой можно столкнуться при таком подходе.
Ситуация:
Вы берете список доступных пользователю организаций и передаете его в параметр &СписокОрганизаций. В запросе пишете:
ГДЕ Организация В (&СписокОрганизаций)
Проблема:
Пользователь не видит данных, если ему дан доступ к Группе справочника, а в документах используются Элементы, входящие в эту группу.
Оператор В проверяет точное равенство ссылок.
СсылкаНаЭлемент не равна СсылкаНаГруппу.
В стандартном RLS часто используются скрытые механизмы или шаблоны, которые учитывают иерархию. В ручном запросе этого нет.
Решение:
При программном формировании отбора у вас есть два пути:
ГДЕ Организация В ИЕРАРХИИ (&СписокОрганизаций)
Внимание: это может быть медленно, так как создает дополнительные соединения или временные таблицы.
// Пример логики перед запросом
МассивЭлементов = ПолучитьВсеЭлементыИзГрупп(СписокГрупп);
Запрос.УстановитьПараметр("СписокОрганизаций", МассивЭлементов);
В (&СписокОрганизаций).
Если вы столкнулись с подобной проблемой, выполните следующие шаги:
В ИЕРАРХИИ или разворачивайте список элементов программно до выполнения запроса.