При разработке сложных механизмов интеграции и обмена данными в среде 1С:Предприятие 8.3, особенно при использовании СУБД PostgreSQL, разработчики часто сталкиваются с неочевидной на первый взгляд ошибкой: «ОШИБКА: число столбцов в соединениях ограничено 32767» (SQLSTATE 54000). Эта проблема становится особенно острой при попытке соединить таблицы с использованием полей составного типа, таких как УникальныйИдентификаторИсточника в типовом регистре сведений СоответствияОбъектовИнформационныхБаз.
В данной статье мы подробно разберем природу возникновения этой ошибки, выясним, почему привычные методы типизации могут не срабатывать на новых версиях платформы, и рассмотрим эффективные способы обхода этого ограничения.
Давайте проанализируем ситуацию на уровне взаимодействия платформы 1С и СУБД PostgreSQL. В системе 1С поле составного типа (например, «Любая ссылка» или определяемый тип, включающий сотни объектов) не является одной колонкой в таблице базы данных. Для обеспечения ссылочной целостности и возможности хранения разных типов данных, платформа создает для каждого возможного типа в составе поля две колонки: одну для хранения самого значения (UID ссылки) и одну для идентификатора типа.
Если в вашей конфигурации (например, ERP 2.5 или Комплексная автоматизация) в определяемый тип, используемый в регистре СоответствияОбъектовИнформационныхБаз, включено 500 различных документов и справочников, то одно только это поле порождает в SQL-таблице около 1000 колонок. Когда мы выполняем ЛЕВОЕ СОЕДИНЕНИЕ, PostgreSQL пытается построить виртуальную таблицу результата. Лимит PostgreSQL в 32767 колонок кажется огромным, но при соединении нескольких «тяжелых» таблиц с разветвленными составными типами этот предел легко преодолевается. Платформа 1С при генерации SQL-запроса разворачивает все возможные поля-хранилища, что и приводит к падению запроса еще на этапе планирования в СУБД.
Рассмотрим пример кода, который часто приводит к ошибке:
ВЫБРАТЬ
ПроизводствоБезЗаказа.Ссылка КАК ПроизводствоБезЗаказа,
Соответствия.УникальныйИдентификаторПриемника
ИЗ
Документ.ПроизводствоБезЗаказа КАК ПроизводствоБезЗаказа
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СоответствияОбъектовИнформационныхБаз КАК Соответствия
ПО (ПроизводствоБезЗаказа.Ссылка = (ВЫРАЗИТЬ(Соответствия.УникальныйИдентификаторИсточника КАК Документ.ПроизводствоБезЗаказа)))
ГДЕ
ПроизводствоБезЗаказа.Проведен
Проанализируем ситуацию: разработчик пытается ограничить тип с помощью ВЫРАЗИТЬ непосредственно в условии соединения. Однако в последних версиях платформы (начиная с 8.3.24) логика построения SQL-запросов изменилась. Платформа может сначала сформировать структуру соединения для всей таблицы регистра (со всеми его сотнями колонок), а уже потом пытаться применить фильтр типа. В итоге запрос «взрывается» по количеству колонок до того, как фильтрация вступит в силу.
Самый простой и эффективный способ — использовать существующую архитектуру регистра СоответствияОбъектовИнформационныхБаз. В типовых решениях этот регистр имеет измерение ТипИсточника или ТипПриемника, в котором хранится строковое представление типа метаданных. Фильтрация по строке или значению перечисления позволяет оптимизатору СУБД отсечь лишние данные до выполнения дорогостоящих соединений.
Разберем правильный подход с использованием строковой фильтрации:
ВЫБРАТЬ
Соответствия.УникальныйИдентификаторПриемника,
Соответствия.УникальныйИдентификаторИсточника
ПОМЕСТИТЬ ВТ_ОтфильтрованныеДанные
ИЗ
РегистрСведений.СоответствияОбъектовИнформационныхБаз КАК Соответствия
ГДЕ
Соответствия.ТипИсточника = "ДокументСсылка.ПроизводствоБезЗаказа";
// Теперь соединяем только с узкой временной таблицей
ВЫБРАТЬ
Производство.Ссылка,
ВТ.УникальныйИдентификаторПриемника
ИЗ
Документ.ProductionWithoutOrder КАК Производство
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ОтфильтрованныеДанные КАК ВТ
ПО Производство.Ссылка = ВТ.УникальныйИдентификаторИсточника
Если использование строкового поля по каким-то причинам невозможно или неэффективно, мы должны принудительно заставить платформу 1С создать «узкую» таблицу в памяти SQL. Для этого используется помещение данных во временную таблицу с явным приведением типов в списке выбора, а не в условии соединения.
Рассмотрим по шагам этот алгоритм:
ВЫБРАТЬ используем ВЫРАЗИТЬ для каждого составного поля.ГДЕ ограничиваем выборку через оператор ССЫЛКА.Посмотрим на пример реализации:
ВЫБРАТЬ
ВЫРАЗИТЬ(Соответствия.УникальныйИдентификаторИсточника КАК Документ.ПроизводствоБезЗаказа) КАК ИсточникСсылка,
Соответствия.УникальныйИдентификаторПриемника КАК ПриемникUID
ПОМЕСТИТЬ ВТ_СоответствияТипизированные
ИЗ
РегистрСведений.СоответствияОбъектовИнформационныхБаз КАК Соответствия
ГДЕ
Соответствия.УникальныйИдентификаторИсточника ССЫЛКА Документ.ПроизводствоБезЗаказа;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ДокументОбъект.Ссылка,
ВТ.ПриемникUID
ИЗ
Документ.ПроизводствоБезЗаказа КАК ДокументОбъект
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_СоответствияТипизированные КАК ВТ
ПО ДокументОбъект.Ссылка = ВТ.ИсточникСсылка
В данном случае во временную таблицу ВТ_СоответствияТипизированные попадут только две колонки на уровне SQL: ссылка на документ ПроизводствоБезЗаказа и идентификатор приемника. Ошибка 54000 гарантированно исчезнет, так как общее количество колонок в соединении будет минимальным.
Выясним еще одну причину возникновения проблемы: обращение через точку к полям составного типа внутри условия ПО. Например, условие ПО Т1.Ссылка = Т2.ПолеСоставногоТипа.Ссылка заставляет платформу выполнять неявное соединение со всеми таблицами, входящими в этот тип.
Для оптимизации рекомендуется использовать следующий синтаксис:
// Вместо прямой связи используем дополнительное условие по типу
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СоответствияОбъектовИнформационныхБаз КАК Соответствия
ПО ПроизводствоБезЗаказа.Ссылка = Соответствия.УникальныйИдентификаторИсточника
И Соответствия.УникальныйИдентификаторИсточника ССЫЛКА Документ.ПроизводствоБезЗаказа
Хотя этот метод кажется проще, использование временных таблиц (Решение №2) остается более надежным для высоконагруженных систем на PostgreSQL, так как оно дает более предсказуемый план запроса.
Проанализировав проблему, мы можем сделать вывод, что ошибка 54000 — это сигнал о том, что запрос перегружен неявными связями из-за особенностей работы с составными типами в 1С. Чтобы избежать падения системы, придерживайтесь следующих правил:
ЛюбаяСсылка).ВЫРАЗИТЬ в списке полей ВЫБРАТЬ при наполнении временной таблицы, чтобы «схлопнуть» составной тип до одного конкретного.ГДЕ.Соблюдение этих рекомендаций не только решит проблему с лимитом колонок в PostgreSQL, но и значительно повысит общую производительность ваших запросов за счет сокращения объема обрабатываемых данных на уровне СУБД. Для автоматического выявления подобных мест в конфигурации можно использовать обработку для проверки запросов на лишнюю выборку и разыменование полей составного типа.