При работе с крупными типовыми конфигурациями на платформе 1С:Предприятие 8.3 (такими как «Бухгалтерия предприятия 3.0») разработчики часто сталкиваются с ситуацией, когда стандартный код, работающий годами, внезапно начинает выдавать ошибку: «Построенный запрос к СУБД использует слишком много таблиц». Эта проблема особенно актуальна при попытке построения дерева подчиненных документов или использовании структуры подчиненности. Разберем детально, почему это происходит, как платформа взаимодействует с базой данных и как исправить ситуацию.
Рассмотрим типовой сценарий, представленный в вопросе. Программист выполняет запрос к объекту метаданных КритерийОтбора.СвязанныеДокументы. Код выглядит следующим образом:
Если Не Метаданные.КритерииОтбора.СвязанныеДокументы.Тип.СодержитТип(ТипЗнч(ЗначениеКритерияОтбора)) Тогда
Возврат Неопределено;
КонецЕсли;
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| СвязанныеДокументы.Ссылка
|ИЗ
| КритерийОтбора.СвязанныеДокументы(&ЗначениеКритерияОтбора) КАК СвязанныеДокументы";
Запрос.УстановитьПараметр("ЗначениеКритерияОтбора", ЗначениеКритерияОтбора);
Возврат Запрос.Выполнить().Выгрузить();
На первый взгляд, код абсолютно корректен. Однако при переносе базы из файлового режима на клиент-серверный вариант (MS SQL Server) выполнение этого фрагмента прерывается системной ошибкой. Проанализируем ситуацию: в файловом режиме лимиты на количество таблиц в запросе практически отсутствуют или обрабатываются внутренним движком 1С иначе, тогда как в SQL-варианте вступают в силу ограничения конкретной СУБД.
Для того чтобы понять, откуда берется «слишком много таблиц», нам нужно заглянуть «под капот» платформы 1С. Когда мы пишем в языке запросов обращение к КритерийОтбора, платформа транслирует это в SQL-представление. Критерий отбора — это не физическая таблица, а виртуальный объект, который собирает данные из множества различных таблиц документов, указанных в его составе.
На уровне СУБД этот запрос превращается в огромную конструкцию, состоящую из множества операторов UNION ALL. Каждая ветка UNION ALL обращается к отдельной таблице документа, где есть реквизит, входящий в состав данного критерия. Если в конфигурации «Бухгалтерия предприятия 3.0» в критерий СвязанныеДокументы включено, например, 300 различных типов документов, то итоговый SQL-запрос будет пытаться объединить 300 таблиц.
Здесь мы сталкиваемся с жестким ограничением старых версий Microsoft SQL Server. В частности, MS SQL Server 2005 имеет лимит: не более 256 таблиц в одном запросе. Если количество объектов в составе критерия превышает этот лимит, СУБД просто отказывается выполнять запрос.
Проанализировав ситуацию, мы можем предложить несколько вариантов решения задачи, в зависимости от инфраструктуры и возможности внесения изменений в конфигурацию.
Как было верно замечено в обсуждении, ограничение в 256 таблиц было актуально для SQL Server 2005. Начиная с версии SQL Server 2008 и выше (2012, 2016, 2019 и т.д.), этот лимит был значительно расширен. Теперь он зависит не от фиксированного числа, а от доступной оперативной памяти и сложности дерева плана запроса.
Если ваша организация до сих пор использует сервер 20-летней давности, это становится критическим препятствием для работы современных релизов 1С. Рассмотрим шаги по обновлению:
Если обновить сервер в данный момент невозможно, проанализируем состав объекта КритерийОтбора.СвязанныеДокументы в метаданных. В типовых конфигурациях 1С в этот критерий часто включены все возможные документы, включая те, которые могут не использоваться в вашем учете (например, специфические отраслевые документы или документы по зарплате в базе, где ведется только бухгалтерия).
Посмотрим, что можно сделать:
КритерииОтбора -> СвязанныеДокументы.Если мы не хотим менять состав критерия (чтобы не снимать объект с поддержки), мы можем изменить сам алгоритм получения данных. Вместо одного «тяжелого» запроса ко всему критерию, мы можем выполнить серию «легких» запросов к конкретным таблицам документов. Рассмотрим пример реализации такого подхода:
Функция ПолучитьСвязанныеДокументыОптимизировано(ЗначениеКритерия)
ТаблицаРезультат = Новый ТаблицаЗначений;
ТаблицаРезультат.Колонки.Добавить("Ссылка");
МетаданныеКритерия = Метаданные.КритерииОтбора.СвязанныеДокументы;
// Перебираем все элементы состава критерия отбора
Для Каждого ЭлементСостава Из МетаданныеКритерия.Состав Цикл
ИмяПути = ЭлементСостава.ПолноеИмя(); // Например, "Документ.РеализацияТоваровУслуг.Реквизит.Сделка"
ЧастиПути = СтрРазделить(ИмяПути, ".");
Если ЧастиПути.Количество() < 2 Тогда Продолжить; КонецЕсли;
ИмяТаблицы = ЧастиПути[0] + "." + ЧастиПути[1];
ИмяРеквизита = ЧастиПути[3];
ЗапросКОбъекту = Новый Запрос;
ЗапросКОбъекту.Текст = "ВЫБРАТЬ Ссылка ИЗ " + ИмяТаблицы + " ГДЕ " + ИмяРеквизита + " = &Значение";
ЗапросКОбъекту.УстановитьПараметр("Значение", ЗначениеКритерия);
Выборка = ЗапросКОбъекту.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НоваяСтрока = ТаблицаРезультат.Добавить();
НоваяСтрока.Ссылка = Выборка.Ссылка;
КонецЦикла;
КонецЦикла;
Возврат ТаблицаРезультат;
КонецФункции
Преимущества этого метода: мы полностью уходим от ограничения на количество таблиц, так как каждый запрос обращается только к одной таблице. Недостатки: скорость выполнения может быть ниже из-за большого количества обращений к СУБД, однако для задачи поиска связанных документов (где обычно ищется конкретный родитель) это вполне приемлемо.
Подведем итог. Проблема с «лишними таблицами» — это классический конфликт между растущей сложностью современных конфигураций 1С и устаревшей инфраструктурой. Платформа 1С:Предприятие при обращении к КритерийОтбора генерирует сложный SQL-запрос с UNION ALL, число ветвей в котором равно количеству типов документов в критерии. Чтобы избежать ошибок в будущем, наилучшим решением является переход на SQL Server версии 2008 и выше, либо использование PostgreSQL. Программные же методы обхода стоит рассматривать лишь как временную меру до планового обновления серверов.