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

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

Довольно часто разработчики сталкиваются с ситуацией, когда программный код, идеально работающий под учетной записью администратора, начинает критически тормозить или вовсе «вешать» сессию у обычного пользователя. Рассмотрим типичный случай: кнопка «Заполнить» выполняет запрос и перебирает документы за год для заполнения табличной части (ТЧ). Под полными правами процесс занимает минуту, а под обычными — система перестает отвечать. Проанализируем причины этого явления и разберем эффективные способы оптимизации.

Причина 1: Влияние механизма RLS (Row Level Security)

Когда у пользователя нет полных прав, платформа 1С автоматически модифицирует каждый запрос к базе данных, добавляя в него условия ограничения доступа на уровне записей. Проанализируем, что происходит «под капотом»:

  1. Раздувание SQL-запроса: Простой запрос превращается в сложную конструкцию с множеством соединений (JOIN) с таблицами прав.
  2. Неоптимальные планы выполнения: SQL-оптимизатор может выбрать неэффективный план из-за сложности условий RLS, что приводит к полному сканированию таблиц (Table Scan) вместо поиска по индексам.
  3. Проверка прав при обращениях через точку: Это самый критичный момент. Если в коде используется обращение Строка.Ссылка.Поле, система для каждой строки выполняет отдельный микро-запрос, который под обычными правами обременен проверкой RLS.

Причина 2: Алгоритмическая сложность циклов

Рассмотрим фрагмент кода, который часто становится причиной «зависания»:


Для Каждого СтрокаИТ из ИтоговаяТаблица Цикл
    Для Каждого СтрокаПлана из Объект.Лоты Цикл            
        Если СтрокаПлана.ЛотСсылка.Исходная = СтрокаИТ.ЛотСсылка Тогда 
            // Какое-то действие
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

В данном примере мы видим вложенный цикл. Если в ИтоговаяТаблица 500 строк, а в Объект.Лоты 1500 строк, то проверка выполнится 750 000 раз. Если внутри этой проверки есть обращение через точку (ЛотСсылка.Исходная), то система попытается выполнить сотни тысяч мелких запросов к БД. Под полными правами спасает кэш объектов, но под RLS проверка прав на каждый такой «чих» убивает производительность.

Решение 1: Использование привилегированного режима

Самый быстрый способ вернуть скорость администратора обычному пользователю — выполнить тяжелый участок кода в привилегированном режиме. В этом режиме проверки RLS игнорируются.

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

Важно: Этот метод следует использовать только тогда, когда вы уверены, что пользователю допустимо видеть эти данные в рамках конкретной обработки, несмотря на его ограничения прав.

Решение 2: Оптимизация поиска в коллекции

Вместо перебора всей табличной части во вложенном цикле, воспользуемся методом НайтиСтроки() или объектом Соответствие. Это позволит сократить сложность алгоритма. Рассмотрим, как переписать неоптимальный код:


// 1. Выгружаем ТЧ во временную таблицу для быстрой работы
ТаблицаЛотов = Объект.Лоты.Выгрузить();

// 2. Чтобы избежать обращений через точку в цикле, 
// заранее добавим нужные данные в колонки таблицы
ТаблицаЛотов.Колонки.Добавить("ИсходнаяЛотСсылка");
Для Каждого Стр Из ТаблицаЛотов Цикл
    // Это обращение сработает 1500 раз, а не 750 000
    Стр.ИсходнаяЛотСсылка = Стр.ЛотСсылка.Исходная; 
КонецЦикла;

// 3. Используем поиск вместо вложенного цикла
ПараметрыПоиска = Новый Структура("ИсходнаяЛотСсылка");
Для Каждого СтрокаИТ из ИтоговаяТаблица Цикл
    ПараметрыПоиска.ИсходнаяЛотСсылка = СтрокаИТ.ЛотСсылка;
    НайденныеСтроки = ТаблицаЛотов.НайтиСтроки(ПараметрыПоиска);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        // Обновляем существующую строку
        ЗаполнитьЗначенияСвойств(НайденныеСтроки[0], СтрокаИТ);
    Иначе
        // Добавляем новую
        НоваяСтр = ТаблицаЛотов.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтр, СтрокаИТ);
    КонецЕсли;
КонецЦикла;

// 4. Загружаем результат обратно
Объект.Лоты.Загрузить(ТаблицаЛотов);

Решение 3: Подготовка данных через запрос

Лучший способ борьбы с медленной работой RLS и обращениями через точку — получение всех необходимых данных одним запросом. Проанализируем ситуацию: если нам нужно сравнить текущие строки ТЧ с новыми данными, мы можем поместить ТЧ во временную таблицу в запросе.

Выполним следующие шаги:

  1. Передадим текущую табличную часть в запрос как параметр.
  2. В самом запросе через ЛЕВОЕ СОЕДИНЕНИЕ или ПОЛНОЕ СОЕДИНЕНИЕ сопоставим данные объекта с данными из базы.
  3. В запросе сразу выберем поля через точку (например, Документ.Ссылка.Исходная). Платформа сделает это одним эффективным SQL-соединением.
  4. Полученный результат запроса просто загрузим в табличную часть методом Загрузить().

Это позволит сократить время выполнения с нескольких минут до пары секунд, так как основная работа ляжет на СУБД, которая гораздо эффективнее справляется с сопоставлением больших массивов данных, чем встроенный язык 1С.

Рекомендации по диагностике

Если вы не уверены, какой именно участок кода тормозит, выполните следующие действия:

Таким образом, для решения проблемы «зависания» без полных прав мы должны минимизировать количество обращений к базе данных внутри циклов, избегать вложенных переборов коллекций и, по возможности, переносить логику обработки данных в запросы или привилегированные модули.

← На главную