Как исправить ошибку «Построенный запрос к СУБД использует слишком много таблиц» в 1С?

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

При формировании тяжелых отчетов или выполнении сложных аналитических запросов разработчики 1С периодически сталкиваются с сообщением об ошибке СУБД: «Построенный запрос к СУБД использует слишком много таблиц. Допустимо не более 256» (код ошибки Microsoft SQL Server: native=102 или Msg 106). Примечательно, что у пользователей с полными правами отчет может формироваться корректно, а сбой происходит исключительно у пользователей с ограниченными правами доступа.

Разберем природу этого поведения платформы, проанализируем механизм генерации SQL-запроса и рассмотрим практические способы решения проблемы.

Почему возникает эта ошибка

Выясним причину, по которой безобидный на первый взгляд запрос в 1С превращается в гигантскую конструкцию на уровне СУБД. Проблема возникает на стыке двух механизмов платформы: разыменования полей составного ссылочного типа и механизма ограничения прав на уровне записей (RLS).

  1. Разыменование составного типа данных. Предположим, у регистра есть измерение Документ с типом ДокументСсылка (без ограничения конкретными видами документов). Как только в запросе к регистру появляется обращение через точку к реквизиту ссылки (например, Регистр.Документ.Дата), транслятор платформы не может заранее знать, ссылка какого именно вида хранится в строке. Платформа вынуждена сформировать конструкцию CASE WHEN ... THEN ... и выполнить неявное левое соединение (LEFT OUTER JOIN) со всеми физическими таблицами документов, входящих в состав этого типа. Если в конфигурации 100 видов документов, к запросу автоматически добавляется 100 соединений.
  2. Влияние RLS (ограничения доступа на уровне записей). Если у пользователя включен RLS, платформа обязана проверить права на чтение каждого из этих документов. К каждой из присоединенных таблиц СУБД подмешивает условия проверки прав (подзапросы к таблицам групп пользователей, значений доступа, регистров сведений прав). Число участвующих таблиц мгновенно возрастает в несколько раз и легко перешагивает лимит в 256 таблиц для одного оператора SELECT.

Способ 1. Уточнение типа ссылки через ВЫРАЗИТЬ и ССЫЛКА

Самое правильное и производительное архитектурное решение — исключить неявные соединения со всеми таблицами метаданных в запросе 1С. Если мы заранее знаем, к каким именно типам документов мы обращаемся, необходимо явно ограничить состав типов с помощью конструкций ВЫРАЗИТЬ и ССЫЛКА.

Посмотрим на пример правильного ограничения типа поля в запросе:


ВЫБРАТЬ
    ВЫРАЗИТЬ(Права.Документ КАК Документ.РеализацияТоваровУслуг).Дата КАК ДатаДокумента
ИЗ
    РегистрСведений.ПраваДоступа КАК Права
ГДЕ
    Права.Документ ССЫЛКА Документ.РеализацияТоваровУслуг

В этом случае платформа 1С выполнит соединение только с одной физической таблицей Документ.РеализацияТоваровУслуг, и правила RLS будут применены только к ней. Если типов несколько, их можно обработать конструкцией ВЫБОР КОГДА ... ТОГДА с явным приведением через ВЫРАЗИТЬ для каждого типа.

Способ 2. Ограничение типов реквизита в метаданных

Проанализируем структуру метаданных конфигурации. Зачастую разработчики выбирают общий составной тип ЛюбаяСсылка или ДокументСсылка «с запасом», хотя в измерении или реквизите фактически хранятся только 2–3 конкретных вида документов. Ограничение списка допустимых типов в конфигураторе напрямую сократит количество генерируемых платформой LEFT JOIN и предотвратит падение на уровне СУБД.

Способ 3. Разбиение запроса с использованием временных таблиц

Лимит СУБД действует в рамках одного выражения SELECT. Если запрос переписать в виде пакетного запроса с использованием временных таблиц, лимит таблиц для каждого отдельного запроса в пакете рассчитывается заново.

Рассмотрим структуру поэтапной выборки:

  1. В первом запросе пакета получаем только сами ссылки на документы из регистра во временную таблицу без обращения к их реквизитам через точку:
    
    ВЫБРАТЬ
        Регистр.Документ КАК Документ
    ПОМЕСТИТЬ ВТ_ИсходныеДокументы
    ИЗ
        РегистрСведений.ДанныеКОбработке КАК Регистр;
    
  2. Во втором запросе соединяем временную таблицу только с теми физическими таблицами документов, реквизиты которых нам действительно нужны, либо отбираем данные порциями по видам документов через ОБЪЕДИНИТЬ ВСЕ.

Способ 4. Использование связей наборов данных в СКД

Если отчет строится с использованием Системы компоновки данных (СКД), проблему можно решить разделением источников данных. Вместо того чтобы объединять все таблицы в одном тексте запроса, создадим два независимых набора данных-запроса:

  1. Первый набор данных выбирает данные основного регистра (со ссылочным полем Документ).
  2. Второй набор данных выбирает необходимые реквизиты (например, дату и номер) конкретных видов документов.
  3. Связывание выполняется на вкладке Связи наборов данных. В этом случае платформа сформирует к СУБД раздельные запросы, а соединение результирующих строк выполнит в оперативной памяти сервера приложений 1С.

Способ 5. Использование привилегированного режима

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


УстановитьПривилегированныйРежим(Истина);
Попытка
    Результат = Запрос.Выполнить();
Исключение
    УстановитьПривилегированныйРежим(Ложь);
    ВызватьИсключение;
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь);

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

Способ 6. Переход на производительный режим RLS (RLS по ключам доступа)

В конфигурациях на базе Библиотеки стандартных подсистем (БСП) рекомендуется использовать современный режим ограничения прав (производительный RLS). В отличие от устаревшего шаблонизированного RLS, проверка доступа в производительном режиме опирается на предварительно рассчитанные ключи доступа в специализированных регистрах. Это минимизирует количество подзапросов и существенно снижает нагрузку на синтаксический анализатор и оптимизатор Microsoft SQL Server.

← На главную