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