Почему медленно работает запрос подсчета количества записей с RLS в 1С и как это исправить?

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

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

Причина разницы в скорости динамического списка и отдельного запроса

Рассмотрим, как платформа 1С и СУБД обрабатывают данные в обоих случаях:

  1. Динамический список работает постранично. При открытии формы СУБД считывает данные порциями (используются конструкции SQL TOP или OFFSET FETCH). Ограничения RLS проверяются только для той небольшой выборки строк, которая физически помещается на экране. За счет этого форма списка открывается практически мгновенно даже на таблицах с 1,5 миллионами документов.
  2. Агрегатный запрос выполняет полное сканирование. Запрос с агрегатными функциями вида КОЛИЧЕСТВО или СУММА и ключевым словом ВЫБРАТЬ РАЗРЕШЕННЫЕ вынужден обойти всю таблицу. В результате платформа подставляет сложные подзапросы RLS для каждой из 1,5 миллионов записей. Вместо работы по индексам СУБД выполняет полное сканирование (Table Scan) или использует ресурсоемкие операторы типа Nested Loops.
  3. Лишние операции с ключом РАЗЛИЧНЫЕ. Конструкция КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) требует от сервера СУБД дополнительной сортировки, уникализации и хэширования записей в оперативной памяти или базе tempdb, что еще сильнее снижает скорость.

Способ 1. Использование привилегированного режима и компоновщика настроек списка

Наиболее эффективный способ быстро посчитать количество документов с учетом отборов, которые пользователь установил на форме, — отключить динамическую проверку RLS и применить явный фильтр на сервере.

Для этого в серверной функции включается привилегированный режим через УстановитьПривилегированныйРежим(Истина), а отборы из динамического списка извлекаются с помощью компоновщика настроек:


&НаСервере
Функция ПолучитьКоличествоЗаявокНаСервере()
    
    // Включаем привилегированный режим для отключения механизма RLS
    УстановитьПривилегированныйРежим(Истина);
    
    // Извлекаем настройки и схему из динамического списка формы
    Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
    Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
    
    // Формируем макет компоновки
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляОбъектовКонсолидации"));
    
    // Настраиваем запрос компоновки
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
    
    // Вычисляем количество строк в результате
    Количество = 0;
    Пока Истина Цикл
        ЭлементРезультата = ПроцессорКомпоновки.Следующий();
        Если ЭлементРезультата = Неопределено Тогда
            Прервать;
        КонецЕсли;
        Количество = Количество + 1;
    КонецЦикла;
    
    Возврат Количество;
    
КонецФункции

Если в привилегированном режиме требуется ограничить данные правами конкретного пользователя, в секцию ГДЕ запроса передаются явные параметры (например, массив доступных организаций или подразделений текущего пользователя).

Способ 2. Оптимизация текста запроса

Если запрос к базе данных выполняется без использования компоновщика СКД, избавимся от неэффективных конструкций. Заменим КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) на простой подсчет первичных ключей КОЛИЧЕСТВО(Ссылка) или КОЛИЧЕСТВО(1):


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	КОЛИЧЕСТВО(1) КАК КоличествоЗаявок
    |ИЗ
    |	Документ.ВТК_Документ КАК ВТК_Документ
    |ГДЕ
    |	ВТК_Документ.Организация В (&СписокОрганизаций)";

Запрос.УстановитьПараметр("СписокОрганизаций", ДоступныеОрганизацииПользователя);

Исключение ключевого слова РАЗЛИЧНЫЕ снизит нагрузку на СУБД, так как серверу не придется группировать и сортировать данные перед подсчетом.

Альтернативные архитектурные решения

  1. Перевод RLS в «Производительный режим» (RLS 2.0). В современных конфигурациях на базе БСП стандартные проверки RLS «на лету» меняют на высокопроизводительный режим. Права рассчитываются заранее при изменении объектов и записываются в регистр КлючиДоступаКДанным. В этом случае запрос ВЫБРАТЬ РАЗРЕШЕННЫЕ выполняет соединение по индексам и отрабатывает быстро.
  2. Асинхронный (фоновый) подсчет. Вынесем длительный расчет количества в фоновое задание с помощью ФоновыеЗадания.Выполнить(). Интерфейс формы не будет блокироваться, а число документов появится на форме по окончании выполнения фоновой задачи.
  3. Кэширование результатов. Если информация о количестве не требует секундной точности, рассчитываем агрегаты периодически по расписанию и сохраняем результаты в разрезе пользователей в специальный регистр сведений. Считывание готового значения из регистра происходит моментально.
← На главную