Почему зависает запрос 1С с конструкциями РАЗРЕШЕННЫЕ, РАЗЛИЧНЫЕ и ПЕРВЫЕ и как это исправить?

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

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


ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ ПЕРВЫЕ 51
	ТаблицаСправочника.AB_Партнер КАК AB_Партнер
ИЗ
	Справочник.Номенклатура КАК ТаблицаСправочника
ГДЕ
	ТаблицаСправочника.ВидНоменклатуры = &ВидНоменклатуры

На первый взгляд запрос кажется легковесным. Однако при выполнении в файловой базе или под пользователем с ограниченными правами время ожидания ответа может исчисляться минутами. Проанализируем причины такого поведения и разберем варианты решения проблемы.

Выясним причину падения производительности

Зависание происходит из-за специфики совместной работы нескольких механизмов платформы 1С и СУБД:

  1. Ограничение прав доступа (RLS): Ключевое слово РАЗРЕШЕННЫЕ на лету подставляет в запрос вложенные условия проверки прав. Если у пользователя включен RLS на справочник Номенклатура или связанный справочник, итоговый SQL-запрос существенно усложняется.
  2. Иключение дублей (РАЗЛИЧНЫЕ) совместно с ПЕРВЫЕ: Чтобы вернуть первые 51 уникальное значение, СУБД не может остановиться на первых найденных 51 записях. Ей приходится полностью просканировать таблицу, применить RLS, исключить дубликаты по всему объему данных и лишь затем отсечь первые 51 запись.
  3. Ограничения файлового движка: Файловая СУБД 1С не имеет продвинутого оптимизатора запросов. При выполнении сложных выборок с отбором уникальных значений и проверкой прав файловый движок переходит к полному сканированию таблицы в памяти.
  4. Отсутствие явно заданного порядка: Использование конструкции ПЕРВЫЕ без ключевого слова УПОРЯДОЧИТЬ ПО не дает СУБД опереться на существующие индексы таблицы.

Способ 1. Замена оператора РАЗЛИЧНЫЕ на предложение СГРУППИРОВАТЬ ПО

Конструкции РАЗЛИЧНЫЕ и СГРУППИРОВАТЬ ПО дают идентичный результат по составу данных, однако оптимизатор СУБД строит для них совершенно разные планы выполнения. Замена РАЗЛИЧНЫЕ на группировку позволяет кардинально ускорить выборку:


ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 51
	ТаблицаСправочника.AB_Партнер КАК AB_Партнер
ИЗ
	Справочник.Номенклатура КАК ТаблицаСправочника
ГДЕ
	ТаблицаСправочника.ВидНоменклатуры = &ВидНоменклатуры
СГРУППИРОВАТЬ ПО
	ТаблицаСправочника.AB_Партнер

На практике этот простой шаг сокращает время выполнения запроса с нескольких минут до 1 секунды.

Способ 2. Оптимизация через временные таблицы

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

  1. Первым запросом выбираем разрешенные данные с фильтром по условию ГДЕ и помещаем их во временную таблицу.
  2. Вторым запросом выбираем уникальные первые записи из уже отфильтрованной временной таблицы.

ВЫБРАТЬ РАЗРЕШЕННЫЕ
	ТаблицаСправочника.AB_Партнер КАК AB_Партнер
ПОМЕСТИТЬ ВТ_Партнеры
ИЗ
	Справочник.Номенклатура КАК ТаблицаСправочника
ГДЕ
	ТаблицаСправочника.ВидНоменклатуры = &ВидНоменклатуры;

ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 51
	ВТ_Партнеры.AB_Партнер КАК AB_Партнер
ИЗ
	ВТ_Партнеры КАК ВТ_Партнеры

В этом случае платформа сначала выполнит проверку RLS и отбор по виду номенклатуры, а обработку уникальности РАЗЛИЧНЫЕ выполнит на уже небольшом объеме данных из временной таблицы.

Способ 3. Настройка индексации и явное приведение типов

Разберем дополнительные настройки на уровне конфигуратора и текста запроса, которые помогают повысить скорость работы:

  1. Индексация поля фильтрации: Убедимся, что у реквизита ВидНоменклатуры в конфигураторе установлено свойство **Параметры индексации** в значение Индексировать или Индексировать с доп. упорядочиванием. Индексировать само выбираемое поле AB_Партнер без индексации поля фильтрации не даст результата.
  2. Явное приведение типов (ВЫРАЗИТЬ): Если реквизит может иметь составной тип или ссылается на другой справочник, явно укажем его тип. Это предотвратит построение неявных левых соединений платфомой:

ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 51
	ВЫРАЗИТЬ(ТаблицаСправочника.AB_Партнер КАК Справочник.Партнеры) КАК AB_Партнер
ИЗ
	Справочник.Номенклатура КАК ТаблицаСправочника
ГДЕ
	ТаблицаСправочника.ВидНоменклатуры = &ВидНоменклатуры
СГРУППИРОВАТЬ ПО
	ТаблицаСправочника.AB_Партнер

Способ 4. Выполнение в привилегированном режиме

Если алгоритм выполняется в фоновом задании или сертифицированном сервисном коде, где не требуется ограничение прав на уровне строк, целесообразно временно отключить RLS с помощью функции УстановитьПривилегированныйРежим(Истина). В этом случае ключевое слово РАЗРЕШЕННЫЕ будет проигнорировано платформой, что исключит подстановку тяжелых подзапросов прав доступа.

← На главную