При работе с большими базами данных в 1С (содержащими миллионы записей) разработчики часто сталкиваются с ситуацией, когда динамический список документа открывается и прокручивается моментально, но попытка програмно посчитать общее количество доступных пользователю документов через отдельный запрос зависает на несколько минут. Проанализируем, почему возникает эта проблема при включенном механизме ограничений на уровне записей (RLS) и как правильно реализовать быстрое получение количества с учетом пользовательских отборов.
Рассмотрим, как платформа 1С и СУБД обрабатывают данные в обоих случаях:
TOP или OFFSET FETCH). Ограничения RLS проверяются только для той небольшой выборки строк, которая физически помещается на экране. За счет этого форма списка открывается практически мгновенно даже на таблицах с 1,5 миллионами документов.КОЛИЧЕСТВО или СУММА и ключевым словом ВЫБРАТЬ РАЗРЕШЕННЫЕ вынужден обойти всю таблицу. В результате платформа подставляет сложные подзапросы RLS для каждой из 1,5 миллионов записей. Вместо работы по индексам СУБД выполняет полное сканирование (Table Scan) или использует ресурсоемкие операторы типа Nested Loops.РАЗЛИЧНЫЕ. Конструкция КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) требует от сервера СУБД дополнительной сортировки, уникализации и хэширования записей в оперативной памяти или базе tempdb, что еще сильнее снижает скорость.Наиболее эффективный способ быстро посчитать количество документов с учетом отборов, которые пользователь установил на форме, — отключить динамическую проверку RLS и применить явный фильтр на сервере.
Для этого в серверной функции включается привилегированный режим через УстановитьПривилегированныйРежим(Истина), а отборы из динамического списка извлекаются с помощью компоновщика настроек:
&НаСервере
Функция ПолучитьКоличествоЗаявокНаСервере()
// Включаем привилегированный режим для отключения механизма RLS
УстановитьПривилегированныйРежим(Истина);
// Извлекаем настройки и схему из динамического списка формы
Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
// Формируем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляОбъектовКонсолидации"));
// Настраиваем запрос компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
// Вычисляем количество строк в результате
Количество = 0;
Пока Истина Цикл
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Если ЭлементРезультата = Неопределено Тогда
Прервать;
КонецЕсли;
Количество = Количество + 1;
КонецЦикла;
Возврат Количество;
КонецФункции
Если в привилегированном режиме требуется ограничить данные правами конкретного пользователя, в секцию ГДЕ запроса передаются явные параметры (например, массив доступных организаций или подразделений текущего пользователя).
Если запрос к базе данных выполняется без использования компоновщика СКД, избавимся от неэффективных конструкций. Заменим КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) на простой подсчет первичных ключей КОЛИЧЕСТВО(Ссылка) или КОЛИЧЕСТВО(1):
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КОЛИЧЕСТВО(1) КАК КоличествоЗаявок
|ИЗ
| Документ.ВТК_Документ КАК ВТК_Документ
|ГДЕ
| ВТК_Документ.Организация В (&СписокОрганизаций)";
Запрос.УстановитьПараметр("СписокОрганизаций", ДоступныеОрганизацииПользователя);
Исключение ключевого слова РАЗЛИЧНЫЕ снизит нагрузку на СУБД, так как серверу не придется группировать и сортировать данные перед подсчетом.
КлючиДоступаКДанным. В этом случае запрос ВЫБРАТЬ РАЗРЕШЕННЫЕ выполняет соединение по индексам и отрабатывает быстро.ФоновыеЗадания.Выполнить(). Интерфейс формы не будет блокироваться, а число документов появится на форме по окончании выполнения фоновой задачи.