Довольно часто разработчики сталкиваются с ситуацией, когда программный код, идеально работающий под учетной записью администратора, начинает критически тормозить или вовсе «вешать» сессию у обычного пользователя. Рассмотрим типичный случай: кнопка «Заполнить» выполняет запрос и перебирает документы за год для заполнения табличной части (ТЧ). Под полными правами процесс занимает минуту, а под обычными — система перестает отвечать. Проанализируем причины этого явления и разберем эффективные способы оптимизации.
Когда у пользователя нет полных прав, платформа 1С автоматически модифицирует каждый запрос к базе данных, добавляя в него условия ограничения доступа на уровне записей. Проанализируем, что происходит «под капотом»:
JOIN) с таблицами прав.Table Scan) вместо поиска по индексам.Строка.Ссылка.Поле, система для каждой строки выполняет отдельный микро-запрос, который под обычными правами обременен проверкой RLS.Рассмотрим фрагмент кода, который часто становится причиной «зависания»:
Для Каждого СтрокаИТ из ИтоговаяТаблица Цикл
Для Каждого СтрокаПлана из Объект.Лоты Цикл
Если СтрокаПлана.ЛотСсылка.Исходная = СтрокаИТ.ЛотСсылка Тогда
// Какое-то действие
КонецЕсли;
КонецЦикла;
КонецЦикла;
В данном примере мы видим вложенный цикл. Если в ИтоговаяТаблица 500 строк, а в Объект.Лоты 1500 строк, то проверка выполнится 750 000 раз. Если внутри этой проверки есть обращение через точку (ЛотСсылка.Исходная), то система попытается выполнить сотни тысяч мелких запросов к БД. Под полными правами спасает кэш объектов, но под RLS проверка прав на каждый такой «чих» убивает производительность.
Самый быстрый способ вернуть скорость администратора обычному пользователю — выполнить тяжелый участок кода в привилегированном режиме. В этом режиме проверки RLS игнорируются.
Для этого вынесем логику заполнения в процедуру общего модуля с установленным флагом «Привилегированный» или воспользуемся методом УстановитьПривилегированныйРежим(Истина) (если код выполняется на сервере).
Важно: Этот метод следует использовать только тогда, когда вы уверены, что пользователю допустимо видеть эти данные в рамках конкретной обработки, несмотря на его ограничения прав.
Вместо перебора всей табличной части во вложенном цикле, воспользуемся методом НайтиСтроки() или объектом Соответствие. Это позволит сократить сложность алгоритма. Рассмотрим, как переписать неоптимальный код:
// 1. Выгружаем ТЧ во временную таблицу для быстрой работы
ТаблицаЛотов = Объект.Лоты.Выгрузить();
// 2. Чтобы избежать обращений через точку в цикле,
// заранее добавим нужные данные в колонки таблицы
ТаблицаЛотов.Колонки.Добавить("ИсходнаяЛотСсылка");
Для Каждого Стр Из ТаблицаЛотов Цикл
// Это обращение сработает 1500 раз, а не 750 000
Стр.ИсходнаяЛотСсылка = Стр.ЛотСсылка.Исходная;
КонецЦикла;
// 3. Используем поиск вместо вложенного цикла
ПараметрыПоиска = Новый Структура("ИсходнаяЛотСсылка");
Для Каждого СтрокаИТ из ИтоговаяТаблица Цикл
ПараметрыПоиска.ИсходнаяЛотСсылка = СтрокаИТ.ЛотСсылка;
НайденныеСтроки = ТаблицаЛотов.НайтиСтроки(ПараметрыПоиска);
Если НайденныеСтроки.Количество() > 0 Тогда
// Обновляем существующую строку
ЗаполнитьЗначенияСвойств(НайденныеСтроки[0], СтрокаИТ);
Иначе
// Добавляем новую
НоваяСтр = ТаблицаЛотов.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтр, СтрокаИТ);
КонецЕсли;
КонецЦикла;
// 4. Загружаем результат обратно
Объект.Лоты.Загрузить(ТаблицаЛотов);
Лучший способ борьбы с медленной работой RLS и обращениями через точку — получение всех необходимых данных одним запросом. Проанализируем ситуацию: если нам нужно сравнить текущие строки ТЧ с новыми данными, мы можем поместить ТЧ во временную таблицу в запросе.
Выполним следующие шаги:
ЛЕВОЕ СОЕДИНЕНИЕ или ПОЛНОЕ СОЕДИНЕНИЕ сопоставим данные объекта с данными из базы.Документ.Ссылка.Исходная). Платформа сделает это одним эффективным SQL-соединением.Загрузить().Это позволит сократить время выполнения с нескольких минут до пары секунд, так как основная работа ляжет на СУБД, которая гораздо эффективнее справляется с сопоставлением больших массивов данных, чем встроенный язык 1С.
Если вы не уверены, какой именно участок кода тормозит, выполните следующие действия:
Таким образом, для решения проблемы «зависания» без полных прав мы должны минимизировать количество обращений к базе данных внутри циклов, избегать вложенных переборов коллекций и, по возможности, переносить логику обработки данных в запросы или привилегированные модули.