При написании сложных запросов в системе 1С:Предприятие программисты часто сталкиваются с двумя вариантами оформления синтаксиса соединений. В одном случае условия ПО (ON) следуют сразу за каждым объявлением таблицы, в другом — накапливаются в конце блока соединений. На первый взгляд может показаться, что это лишь вопрос эстетики или прихоть Конструктора запросов, однако за этим кроются важные механизмы работы СУБД и логики обработки данных.
Рассмотрим детально, как эти конструкции влияют на результат, производительность и читаемость кода. Разберем по шагам ситуации, когда разницы действительно нет, и ситуации, когда ошибка в синтаксисе приведет к неверным данным в отчете.
Проанализируем два способа записи запроса, которые вызвали дискуссию. Для примера возьмем три таблицы: ВТ_Товары, ВТ_Остатки и ВТ_Цены.
Вариант 1: Последовательное соединение (стандартный вид)
В этом варианте каждое соединение завершается своим условием. Это наиболее привычный вид для ручного написания кода.
ВЫБРАТЬ
Товары.Ссылка,
Остатки.Количество,
Цены.Цена
ИЗ
ВТ_Товары КАК Товары
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Остатки КАК Остатки
ПО Товары.Ссылка = Остатки.Номенклатура
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Цены КАК Цены
ПО Товары.Ссылка = Цены.Номенклатура
Вариант 2: Вложенное (накопительное) соединение
Этот вариант часто генерируется Конструктором запросов при использовании сложных связей или перетаскивании таблиц. Условия ПО здесь идут в обратном порядке относительно таблиц.
ВЫБРАТЬ
Товары.Ссылка,
Остатки.Количество,
Цены.Цена
ИЗ
ВТ_Товары КАК Товары
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Остатки КАК Остатки
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Цены КАК Цены
ПО Остатки.Номенклатура = Цены.Номенклатура
ПО Товары.Ссылка = Остатки.Номенклатура
Выясним, есть ли разница в результате для ВНУТРЕННЕГО СОЕДИНЕНИЯ. С точки зрения реляционной алгебры, операция внутреннего соединения обладает свойствами коммутативности и ассоциативности.
Это означает, что для внутреннего соединения порядок таблиц и группировка условий не влияют на итоговый набор строк. Если мы соединяем таблицы А, Б и В, то результат (А + Б) + В будет идентичен результату А + (Б + В). Поэтому, когда в теме форума звучит вопрос «есть ли разница», ответ «нет» справедлив только для внутренних соединений.
Ситуация кардинально меняется, как только мы начинаем использовать ЛЕВОЕ СОЕДИНЕНИЕ. Проанализируем ситуацию, где порядок «вложенности» условий ПО полностью меняет логику запроса.
В последовательном варианте (Вариант 1) вторая таблица присоединяется к первой, а третья — к результату соединения первых двух. Если в таблице ВТ_Остатки нет записи для товара, мы все равно получим строку (так как соединение левое), но с пустыми значениями из ВТ_Цены.
Во вложенном варианте (Вариант 2) сначала происходит соединение таблиц ВТ_Остатки и ВТ_Цены, и только потом этот общий результат присоединяется к ВТ_Товары. Если мы используем ЛЕВОЕ СОЕДИНЕНИЕ внутри вложенного блока, а потом присоединяем его тоже левым соединением, мы можем получить совершенно разные наборы NULL-значений.
Важно помнить: Вложенная запись фактически создает виртуальную подгруппу соединений. Если внутри этой группы стоит ВНУТРЕННЕЕ СОЕДИНЕНИЕ, а снаружи — ЛЕВОЕ, то отсутствие данных в самой «глубокой» таблице может отсечь данные из промежуточной таблицы еще до того, как они попытаются присоединиться к основной.
Рассмотрим, как на это смотрит сервер базы данных (MS SQL Server или PostgreSQL). Многие разработчики опасаются, что «некрасивый» синтаксис заставит сервер работать медленнее.
JOIN в тексте, и перестраивают дерево соединений так, чтобы сначала обрабатывались таблицы с наименьшим количеством строк.Разберем причину появления структуры СОЕДИНЕНИЕ... СОЕДИНЕНИЕ... ПО... ПО.... Это происходит, когда в визуальном редакторе связей вы создаете зависимость, где одна таблица связана сразу с несколькими или когда связи строятся «цепочкой» не от первой таблицы.
Платформа 1С старается сохранить иерархию объектов, которую вы задали в интерфейсе. Однако при нажатии кнопки «ОК» в конструкторе и повторном открытии он часто «нормализует» запрос, приводя его к последовательному виду, если это не меняет логику (для внутренних соединений).
Несмотря на то, что для ВНУТРЕННЕГО СОЕДИНЕНИЯ технической разницы нет, мы рекомендуем придерживаться последовательного стиля (Вариант 1) по следующим причинам:
ПО находится сразу под таблицей. В «накопительном» стиле (Вариант 2) при наличии 5–7 таблиц приходится буквально отсчитывать количество строк сверху и снизу, чтобы понять, что с чем связано (принцип стека).ВНУТРЕННЕГО соединения на ЛЕВОЕ.Проанализировав проблему, мы можем сделать вывод: разница между этими конструкциями для внутренних соединений заключается исключительно в эстетике и читаемости кода. Однако для внешних соединений порядок следования ключевых слов ПО определяет приоритет выполнения операций и может в корне изменить результат выборки. Для обеспечения стабильности и простоты поддержки кода всегда старайтесь приводить запросы к последовательному виду: Таблица1 СОЕДИНЕНИЕ Таблица2 ПО Условие1 СОЕДИНЕНИЕ Таблица3 ПО Условие2.