Почему поиск в табличной части (метод Найти) выполняется долго под обычным пользователем?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

В практике разработки на платформе 1С часто встречается ситуация, когда код, идеально работающий под учетной записью администратора, начинает существенно «тормозить» у обычных пользователей. Особенно ярко это проявляется при работе с табличными частями крупных объектов, таких как Ресурсные спецификации в ERP или сложные документы в УТ 11. Рассмотрим причины этой проблемы и способы её эффективного решения.

Проанализируем ситуацию: Почему «Найти» работает медленно?

Разберем внутренние механизмы платформы. Основная причина медленной работы метода Найти() у обычных пользователей заключается в работе механизма RLS (Record Level Security) — ограничении доступа на уровне записей. Когда программист вызывает метод Найти() у табличной части объекта (например, СправочникОбъект или ДокументОбъект), платформа выполняет следующие действия:

  1. Объектное чтение: Платформа пытается получить данные из оперативной памяти. Если данных нет, выполняется обращение к базе данных.
  2. Проверка прав (RLS): Если у пользователя нет полных прав, платформа обязана проверить доступ к каждой ссылке, находящейся в табличной части. В случае со сложными конфигурациями (ERP, КА), шаблоны RLS могут быть крайне тяжелыми, включая в себя проверки по организациям, подразделениям или группам доступа.
  3. Неявные соединения: При выполнении поиска по колонке со ссылочным типом, SQL-запрос, который генерирует платформа «под капотом», обрастает множеством соединений с таблицами прав доступа. Это превращает элементарную операцию в тяжеловесный процесс.

В случае, описанном в теме, ситуация усугубляется использованием рекурсии. Если поиск в одной табличной части из-за RLS занимает даже 0.5 секунды, то при рекурсивном обходе вложенных спецификаций с глубиной в 10–20 уровней, общее время ожидания легко переваливает за 30 секунд.

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

Самый быстрый и простой способ решить проблему, если бизнес-логика позволяет временно игнорировать ограничения прав доступа (например, в печатной форме, где данные всё равно должны быть выведены). Мы можем принудительно отключить проверку RLS для конкретного участка кода.

Рассмотрим пример реализации:


// Включаем привилегированный режим, чтобы RLS не замедлял поиск
УстановитьПривилегированныйРежим(Истина);

// Выполняем поиск в табличной части
СтрокаМаршрута = Спецификация.Маршруты.Найти(МаршрутыСварки.Сварка, "Маршрут");

// Не забываем отключить, если далее идет код, требующий проверки прав
УстановитьПривилегированныйРежим(Ложь);

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

Решение 2: Выгрузка в Таблицу Значений

Метод Найти() у ТабличнойЧасти (объект метаданных) работает медленнее, чем аналогичный метод у ТаблицыЗначений (универсальная коллекция в памяти). Это связано с тем, что ТаблицаЗначений не является объектом базы данных, и поиск по ней не инициирует повторные проверки прав доступа для каждой строки в контексте владельца.

Посмотрим на алгоритм оптимизации:

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

// Выгружаем ТЧ в таблицу значений
ТЗ_Маршруты = Спецификация.Маршруты.Выгрузить();

// Устанавливаем индекс для ускорения поиска (если строк много)
ТЗ_Маршруты.Индексы.Добавить("Маршрут");

// Теперь поиск будет работать мгновенно даже под пользователем
СтрокаТЗ = ТЗ_Маршруты.Найти(МаршрутыСварки.Сварка, "Маршрут");

Этот метод значительно ускоряет работу, так как обращение к СУБД происходит один раз при выгрузке всей ТЧ, а не при каждом вызове Найти().

Решение 3: Переход на использование запросов с ключевым словом РАЗРЕШЕННЫЕ

Наиболее правильным и архитектурно верным способом является полный отказ от объектной техники в пользу запросов. Запросы позволяют СУБД построить оптимальный план выполнения сразу с учетом всех ограничений прав доступа.

Выясним причину, почему запрос работает быстрее: в запросе мы можем использовать конструкцию ВЫБРАТЬ РАЗРЕШЕННЫЕ, которая фильтрует данные на уровне SQL-сервера за один проход. Если же мы используем рекурсию, лучше собрать все необходимые идентификаторы (ссылки) в массив и выполнить один большой запрос вместо множества мелких в цикле.

Пример оптимизированного получения данных через запрос:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |    СпецификацияМаршруты.Ссылка КАК Спецификация
    |ИЗ
    |    Справочник.РесурсныеСпецификации.Маршруты КАК СпецификацияМаршруты
    |ГДЕ
    |    СпецификацияМаршруты.Ссылка В(&МассивСпецификаций)
    |    И СпецификацияМаршруты.Маршрут = &ИскомыйМаршрут";

Запрос.УстановитьПараметр("МассивСпецификаций", МассивСсылок);
Запрос.УстановитьПараметр("ИскомыйМаршрут", МаршрутыСварки.Сварка);

РезультатЗапроса = Запрос.Выполнить();
// Далее обрабатываем результат...

Подведем итоги и дадим рекомендации

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

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

← На главную