При работе в крупных информационных базах 1С:ERP Управление предприятием разработчики и администраторы часто сталкиваются с критическим падением производительности динамических списков документов (например, «Приобретение товаров и услуг»). Одной из самых распространенных причин этой проблемы является использование механизма ограничения доступа на уровне записей (RLS — Record Level Security), особенно когда у одного пользователя настроен доступ к большому числу конкретных объектов — например, к 42 складам и 38 подразделениям одновременно.
В этой статье мы подробно разберем, почему классический механизм RLS вызывает сильные зависания интерфейса (вплоть до невозможности открыть список или создать новый документ), проанализируем физику этого процесса на уровне СУБД и рассмотрим несколько эффективных практических способов решения данной проблемы — от быстрых настроек в интерфейсе до глубокой оптимизации архитектуры прав.
Для того чтобы понять, как решить проблему, давайте сначала выясним ее причину. При использовании стандартного (классического) режима RLS платформа 1С «на лету» модифицирует каждый запрос, отправляемый к базе данных SQL. Когда пользователь открывает форму списка документов ПТУ (Приобретение товаров и услуг), платформа не просто считывает данные из таблицы документов. Она автоматически добавляет к исходному запросу неявные левые соединения (LEFT JOIN) с таблицами прав доступа.
Основным источником информации о правах в классическом RLS выступает регистр сведений РегистрСведений.ЗначенияГруппДоступа. Когда у пользователя настроены ограничения по нескольким независимым аналитикам (в нашем примере — 42 склада и 38 подразделений), СУБД вынуждена оценивать огромную декартову матрицу возможных пересечений прав для каждой строки документа. Оптимизатор запросов СУБД (будь то Microsoft SQL Server или PostgreSQL) при попытке построить оптимальный план выполнения такого перегруженного запроса сталкивается с так называемым «таймаутом оптимизатора» (Optimizer Timeout). В результате СУБД отказывается от использования индексов и скатывается к полному сканированию таблиц (Table Scan), что приводит к зависаниям и длительному ожиданию открытия формы.
Если вы работаете на современных версиях 1С:ERP (на базе БСП 3.x), то лучшим решением будет полный отказ от классического RLS в пользу производительного режима работы RLS (также известного как RLS через ключи доступа).
Разберем по шагам, как работает этот режим и почему он работает быстрее:
РегистрСведений.КлючиДоступаКОбъектам и РегистрСведений.КлючиДоступаПользователей.Чтобы включить этот режим, выполните следующие действия в интерфейсе программы:
ОбновлениеДоступаНаУровнеЗаписей или воспользуйтесь специальной обработкой по заполнению данных для ограничения доступа, чтобы система рассчитала ключи для уже существующих в базе документов.Если по каким-то причинам вы вынуждены оставаться на классическом RLS, крайне не рекомендуется накладывать ограничения прав непосредственно на элементы справочника Справочники.Склады или Справочники.СтруктураПредприятия. Ограничение по десяткам конкретных элементов — это заведомо проигрышный путь.
Рассмотрим, как оптимизировать структуру данных с помощью групп доступа по аналогии с номенклатурой или партнерами:
Склады добавьте реквизит ГруппаДоступа.В результате СУБД в запросе RLS будет оперировать не десятками индивидуальных записей, а всего лишь несколькими группами доступа. Размер таблицы пересечений прав уменьшится на порядки, и производительность списков мгновенно восстановится.
Для программистов 1С хорошим решением может стать точечная доработка стандартных шаблонов БСП под конкретную бизнес-задачу. Мы можем модифицировать условия RLS, исключив лишние универсальные проверки, которые замедляют СУБД.
Например, в шаблонах ограничений можно найти типовой код БСП:
#Если СтрСодержит(&ВидыДоступаБезГруппДляЗначенияДоступа, ",#Параметр(4),") #Тогда
ВЫБРАТЬ ПЕРВЫЕ 1 ИСТИНА
ИЗ РегистрСведений.ЗначенияГруппДоступа КАК Значения
ГДЕ
Значения.ГруппаДоступа = ГруппыДоступа.Ссылка
И Значения.ЗначениеДоступа = Т.#Параметр(5)
Проанализируем этот участок кода. Мы можем жестко модифицировать это условие в шаблоне конкретно под ваши виды доступа (Склады или Подразделения), минуя универсальные ресурсоемкие проверки параметров БСП. Это позволит сократить количество соединений и передаваемых параметров в SQL-запрос.
Иногда требуется решить проблему «здесь и сейчас», без изменения конфигурации и длительного пересчета ключей доступа. В этом случае отлично помогает наложение жестких отборов непосредственно в форме списка документов.
Выясним причину, почему отбор по организации или периоду ускоряет работу RLS:
Когда пользователь открывает пустой список ПТУ, СУБД пытается применить правила RLS ко всей таблице документов за все время. Если же мы программно или интерактивно устанавливаем жесткий отбор (например, по конкретной Организации или текущему Месяцу), этот фильтр транслируется в секцию WHERE результирующего SQL-запроса.
Поскольку поле Организация хорошо проиндексировано СУБД, база данных сначала быстро отсекает ненужные строки по индексу организации, оставляя лишь малую часть выборки. И уже к этой небольшой выборке строк СУБД применяет тяжелые левые соединения по складам и подразделениям. Нагрузка на сервер снижается в сотни раз, список открывается мгновенно.
Рекомендуется сделать предопределенные отборы (например, по умолчанию показывать документы только за последний месяц) обязательными для пользователей с ограниченными правами.
Если требования безопасности вашей компании допускают это, рассмотрите радикальный, но максимально эффективный с точки зрения производительности вариант — отказ от RLS на уровне чтения списков.
Рассмотрим этот подход подробнее:
ПередЗаписью).Пример кода проверки прав доступа в модуле документа при его записи:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Проверяем, есть ли у текущего пользователя права на запись документа по складу
Доступ Разрешен = ПроверитьДоступКЗначению(ЭтотОбъект.Склад, ПараметрыСеанса.ТекущийПользователь);
Если Не ДоступРазрешен Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru = 'У вас нет прав на создание или изменение документов по складу: '") + ЭтотОбъект.Склад
);
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Этот метод гарантирует абсолютную отзывчивость интерфейса системы (скорость открытия списков будет такой же, как если бы RLS был полностью отключен), так как тяжелые SQL-запросы на проверку прав при чтении больше не выполняются.
Для кардинального решения проблемы медленной работы RLS при большом числе складов и подразделений мы рекомендуем придерживаться следующего плана действий:
ПередЗаписью.