При формировании тяжелых отчетов или выполнении сложных аналитических запросов разработчики 1С периодически сталкиваются с сообщением об ошибке СУБД: «Построенный запрос к СУБД использует слишком много таблиц. Допустимо не более 256» (код ошибки Microsoft SQL Server: native=102 или Msg 106). Примечательно, что у пользователей с полными правами отчет может формироваться корректно, а сбой происходит исключительно у пользователей с ограниченными правами доступа.
Разберем природу этого поведения платформы, проанализируем механизм генерации SQL-запроса и рассмотрим практические способы решения проблемы.
Выясним причину, по которой безобидный на первый взгляд запрос в 1С превращается в гигантскую конструкцию на уровне СУБД. Проблема возникает на стыке двух механизмов платформы: разыменования полей составного ссылочного типа и механизма ограничения прав на уровне записей (RLS).
Документ с типом ДокументСсылка (без ограничения конкретными видами документов). Как только в запросе к регистру появляется обращение через точку к реквизиту ссылки (например, Регистр.Документ.Дата), транслятор платформы не может заранее знать, ссылка какого именно вида хранится в строке. Платформа вынуждена сформировать конструкцию CASE WHEN ... THEN ... и выполнить неявное левое соединение (LEFT OUTER JOIN) со всеми физическими таблицами документов, входящих в состав этого типа. Если в конфигурации 100 видов документов, к запросу автоматически добавляется 100 соединений.SELECT.Самое правильное и производительное архитектурное решение — исключить неявные соединения со всеми таблицами метаданных в запросе 1С. Если мы заранее знаем, к каким именно типам документов мы обращаемся, необходимо явно ограничить состав типов с помощью конструкций ВЫРАЗИТЬ и ССЫЛКА.
Посмотрим на пример правильного ограничения типа поля в запросе:
ВЫБРАТЬ
ВЫРАЗИТЬ(Права.Документ КАК Документ.РеализацияТоваровУслуг).Дата КАК ДатаДокумента
ИЗ
РегистрСведений.ПраваДоступа КАК Права
ГДЕ
Права.Документ ССЫЛКА Документ.РеализацияТоваровУслуг
В этом случае платформа 1С выполнит соединение только с одной физической таблицей Документ.РеализацияТоваровУслуг, и правила RLS будут применены только к ней. Если типов несколько, их можно обработать конструкцией ВЫБОР КОГДА ... ТОГДА с явным приведением через ВЫРАЗИТЬ для каждого типа.
Проанализируем структуру метаданных конфигурации. Зачастую разработчики выбирают общий составной тип ЛюбаяСсылка или ДокументСсылка «с запасом», хотя в измерении или реквизите фактически хранятся только 2–3 конкретных вида документов. Ограничение списка допустимых типов в конфигураторе напрямую сократит количество генерируемых платформой LEFT JOIN и предотвратит падение на уровне СУБД.
Лимит СУБД действует в рамках одного выражения SELECT. Если запрос переписать в виде пакетного запроса с использованием временных таблиц, лимит таблиц для каждого отдельного запроса в пакете рассчитывается заново.
Рассмотрим структуру поэтапной выборки:
ВЫБРАТЬ
Регистр.Документ КАК Документ
ПОМЕСТИТЬ ВТ_ИсходныеДокументы
ИЗ
РегистрСведений.ДанныеКОбработке КАК Регистр;
ОБЪЕДИНИТЬ ВСЕ.Если отчет строится с использованием Системы компоновки данных (СКД), проблему можно решить разделением источников данных. Вместо того чтобы объединять все таблицы в одном тексте запроса, создадим два независимых набора данных-запроса:
Документ).Если логика отчета допускает чтение данных без учета ограничений прав конкретного пользователя, можно временно отключить RLS. Для этого выполнение запроса или построение отчета оборачивается в привилегированный режим с помощью метода УстановитьПривилегированныйРежим(Истина), либо отчет формируется в привилегированном общем модуле.
УстановитьПривилегированныйРежим(Истина);
Попытка
Результат = Запрос.Выполнить();
Исключение
УстановитьПривилегированныйРежим(Ложь);
ВызватьИсключение;
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь);
Важно: Привилегированный режим полностью отключает RLS для запроса, благодаря чему платформе не требуется добавлять подзапросы проверки прав к каждой таблице. Однако применять этот подход нужно с осторожностью, чтобы не нарушить правила информационной безопасности организации.
В конфигурациях на базе Библиотеки стандартных подсистем (БСП) рекомендуется использовать современный режим ограничения прав (производительный RLS). В отличие от устаревшего шаблонизированного RLS, проверка доступа в производительном режиме опирается на предварительно рассчитанные ключи доступа в специализированных регистрах. Это минимизирует количество подзапросов и существенно снижает нагрузку на синтаксический анализатор и оптимизатор Microsoft SQL Server.