В процессе разработки на платформе 1С:Предприятие часто возникают ситуации, когда необходимо связать две таблицы (например, регистры накопления или сведения) по полям, имеющим тип ОпределяемыйТип. Одной из главных опасений разработчиков является вопрос: возникнет ли исключение (аварийное завершение запроса), если типы данных, входящие в состав одного определяемого типа, не полностью совпадают с типами другого? В данной статье мы подробно разберем механизм работы таких соединений, проанализируем структуру хранения данных в СУБД и выясним, как писать такие запросы максимально эффективно.
Для начала разберем природу этого объекта. Определяемый тип — это объект метаданных, который позволяет централизованно описывать составной тип данных и использовать его в различных частях конфигурации. С точки зрения платформы и механизма выполнения запросов, работа с полем, имеющим ОпределяемыйТип, практически идентична работе с обычным составным типом (несколькими типами, выбранными непосредственно в свойствах реквизита).
Рассмотрим ситуацию, описанную в вопросе: мы выполняем левое соединение двух регистров по полям с разными (или частично пересекающимися) определяемыми типами. Проанализируем пример запроса:
ВЫБРАТЬ
Регистр1.Номенклатура,
Регистр2.Количество
ИЗ
РегистрНакопления.Регистр1 КАК Регистр1
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Регистр2 КАК Регистр2
ПО Регистр1.ОбъектСвязи = Регистр2.Владелец
Если в Регистр1.ОбъектСвязи хранится ссылка на Справочник.Договоры, а в описании Регистр2.Владелец этот справочник отсутствует, система не выдаст исключение. В этом случае условие соединения просто вернет значение Ложь, и для данной записи левой таблицы поля правой таблицы будут заполнены значениями NULL. Это происходит потому, что на уровне СУБД сравнение идет не только по идентификатору ссылки, но и по идентификатору типа.
Чтобы понять, почему не возникает ошибки, нам нужно заглянуть "под капот" системы. При использовании составных или определяемых типов в SQL-базе поле превращается в несколько физических колонок. Обычно это:
Когда мы пишем условие соединения ПО Регистр1.ОпределяемыйТип1 = Регистр2.ОпределяемыйТип2, платформа 1С автоматически транслирует это в SQL-запрос, который сравнивает пары колонок (тип и значение). Если в левой таблице тип "Справочник.Контрагенты", а в правой таблице в списке допустимых типов такого справочника вообще нет, SQL-сервер сравнит идентификаторы типов, увидит несовпадение и корректно вернет пустой результат для этой пары строк.
Несмотря на то, что ошибка не возникает, использование "чистого" соединения по определяемому типу может быть крайне медленным на больших объемах данных. Разберем ситуацию: если в определяемый тип входит 20 различных справочников и документов, СУБД приходится выполнять сложную проверку при соединении, что часто приводит к неоптимальному плану запроса и игнорированию индексов.
Для ускорения работы рекомендуется использовать оператор ВЫРАЗИТЬ (или EXPRESS в англоязычном варианте), если нам заранее известно, какой конкретно тип данных мы ожидаем в соединении. Проанализируем правильный подход:
ВЫБРАТЬ
Регистр1.Номенклатура,
Регистр2.Количество
ИЗ
РегистрНакопления.Регистр1 КАК Регистр1
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Регистр2 КАК Регистр2
ПО ВЫРАЗИТЬ(Регистр1.ОбъектСвязи КАК Справочник.Контрагенты) = ВЫРАЗИТЬ(Регистр2.Владелец КАК Справочник.Контрагенты)
ГДЕ
Регистр1.ОбъектСвязи ССЫЛКА Справочник.Контрагенты
Такой подход позволяет платформе обратиться к конкретной таблице данных и использовать наиболее эффективный индекс по уникальной ссылке, минуя сложности сравнения составных типов.
Частой причиной "пропажи" данных при соединении по определяемым типам является различие между значениями Неопределено и ПустаяСсылка. Выясним причину этого поведения:
Неопределено — это отсутствие значения как такового. Оно часто встречается в новых реквизитах или если тип не был инициализирован.ПустаяСсылка — это типизированное значение, которое указывает на "пустой" объект конкретного типа (например, Справочник.Контрагенты.ПустаяСсылка()).Если в одном регистре поле содержит Неопределено, а в другом — пустую ссылку справочника, соединение не сработает. Визуально в отчетах оба поля могут выглядеть пустыми, что вводит разработчика в заблуждение. Проанализируем это при отладке, проверяя именно тип значения в полях.
Рассмотрим еще один важный аспект. Если вы используете определяемые типы в запросах, которые выполняются под пользователем с ограниченными правами (RLS), это может существенно замедлить систему. Платформа 1С для каждой таблицы, входящей в определяемый тип, добавляет подзапросы для проверки прав доступа. Если в типе 15 объектов, SQL-запрос может разрастись до гигантских размеров с множеством JOIN и UNION.
В таких случаях рекомендуется:
ОпределяемомТипе.ВЫРАЗИТЬ.Подводя итог, можно сказать, что соединение по определяемым типам — это безопасная операция с точки зрения стабильности системы (ошибок "Exception" не будет), но она требует внимательности при работе с производительностью и понимания того, как данные представлены на физическом уровне базы данных.