Как работает условие связи с параметрами при левом соединении таблиц в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При написании сложных запросов в платформе 1С:Предприятие разработчики часто сталкиваются с неочевидным поведением связей при использовании ЛЕВОЕ СОЕДИНЕНИЕ, когда в секцию условий соединения ПО помещаются параметры или составные логические выражения с оператором ИЛИ. Разберем механику работы таких запросов, выясним, почему изменение строк документа влияет на выборку и как правильно оптимизировать подобные конструкции.

Анализ логики условия в секции ПО левого соединения

Рассмотрим условие связи, которое часто вызывает вопросы:


ЛЕВОЕ СОЕДИНЕНИЕ Документ.Акция.Получатели КАК АкцияПолучатели
	ПО (АкцииСрезПоследних.Регистратор = АкцияПолучатели.Ссылка)
		И (АкцияПолучатели.Контрагент = &Контрагент
			И АкцияПолучатели.Магазин = &Магазин
		ИЛИ АкцияПолучатели.Контрагент = &Контрагент
			И АкцияПолучатели.Магазин = ЗНАЧЕНИЕ(Справочник.Магазины.ПустаяСсылка))

Проанализируем, как СУБД выполняет это соединение:

  1. Логическая группировка условий: Конструкция с оператором ИЛИ эквивалентна выражению АкцияПолучатели.Контрагент = &Контрагент И АкцияПолучатели.Магазин В (&Магазин, ЗНАЧЕНИЕ(Справочник.Магазины.ПустаяСсылка)).
  2. Поведение левого соединения: Базовый принцип ЛЕВОЕ СОЕДИНЕНИЕ заключается в том, что все строки из левой таблицы (в данном примере — среза последних регистра сведений АкцииСрезПоследних) обязательно остаются в выборке.
  3. Заполнение полей правой таблицы: Если в табличной части правой таблицы (АкцияПолучатели) находится строка, удовлетворяющая условиям по регистратору, контрагенту и магазину, ее данные подтягиваются к левой таблице. Если же подходящей строки нет (например, в документе указан другой контрагент), строка левой таблицы все равно возвращается, но все поля правой таблицы будут содержать значение NULL.

Важный вывод: условие в секции ПО при левом соединении не отсекает записи левой таблицы, а лишь определяет, будут ли заполнены поля присоединяемой правой таблицы или они примут значение NULL.

Почему удаление строк из документа уменьшает количество записей

Разберем ситуацию, когда удаление строк с другими контрагентами из документа и его перепроведение приводит к уменьшению итогового количества строк в запросе. Причина заключается во взаимосвязи структуры данных:

  1. Подчинение регистратору: В периодических регистрах сведений с режимом записи «Подчинение регистратору» набор записей формируется при проведении документа. Если логика проведения создает движения на основании строк табличной части документа, то физическое количество записей в регистре напрямую зависит от количества строк в документе.
  2. Уменьшение левой таблицы: Когда вы удаляете строку из табличной части и перепроводите документ, удаляются соответствующие записи из регистра сведений. Поскольку левой таблицей запроса выступает виртуальная таблица АкцииСрезПоследних, уменьшается исходный набор данных, поступающий на вход соединения.
  3. Неявная трансформация соединения: Если далее в секции ГДЕ присутствует условие, обращающееся к полям правой таблицы без проверки на NULL (например, ГДЕ АкцияПолучатели.Контрагент = &Контрагент), все строки левой таблицы со значением NULL отсекаются. В этом случае ЛЕВОЕ СОЕДИНЕНИЕ фактически работает как ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

Оптимизация запроса и рекомендации по разработке

Использование сложных условий с ИЛИ и прямое соединение виртуальных таблиц с табличными частями документов может приводить к снижению производительности. Рассмотрим практические шаги по оптимизации таких запросов.

Вариант 1. Использование параметров виртуальной таблицы

Рекомендуется передавать предварительные условия непосредственно в параметры виртуальной таблицы «СрезПоследних», а не накладывать их после соединения:


ВЫБРАТЬ
	Акции.Регистратор КАК Регистратор,
	Акции.Скидка КАК Скидка
ИЗ
	РегистрСведений.Акции.СрезПоследних(&Период, ) КАК Акции

Вариант 2. Разделение логики через объединение запросов

Наличие ИЛИ в секции ПО блокирует использование индексов таблиц СУБД. Если требуется обработать логику персональных и общих акций (когда магазин пустой), эффективнее разделить запрос на две части с помощью ОБЪЕДИНИТЬ ВСЕ:


ВЫБРАТЬ
	Акции.Регистратор КАК Регистратор,
	Получатели.Контрагент КАК Контрагент,
	Получатели.Магазин КАК Магазин
ИЗ
	РегистрСведений.Акции.СрезПоследних(&Период, ) КАК Акции
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Акция.Получатели КАК Получатели
			ПО Акции.Регистратор = Получатели.Ссылка
				И Получатели.Контрагент = &Контрагент
				И Получатели.Магазин = &Магазин

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	Акции.Регистратор,
	Получатели.Контрагент,
	Получатели.Магазин
ИЗ
	РегистрСведений.Акции.СрезПоследних(&Период, ) КАК Акции
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Акция.Получатели КАК Получатели
			ПО Акции.Регистратор = Получатели.Ссылка
				И Получатели.Контрагент = &Контрагент
				И Получатели.Магазин = ЗНАЧЕНИЕ(Справочник.Магазины.ПустаяСсылка)

Вариант 3. Выгрузка табличной части во временную таблицу

Табличные части документов в базе данных не имеют индексов по произвольным реквизитам. Для оптимизации запроса поместим данные табличной части во временную таблицу и проиндексируем поля связи:


ВЫБРАТЬ
	ТЧ.Ссылка КАК Регистратор,
	ТЧ.Контрагент КАК Контрагент,
	ТЧ.Магазин КАК Магазин
ПОМЕСТИТЬ ВТ_Получатели
ИЗ
	Документ.Акция.Получатели КАК ТЧ
ГДЕ
	ТЧ.Контрагент = &Контрагент
	И ТЧ.Магазин В (&Магазин, ЗНАЧЕНИЕ(Справочник.Магазины.ПустаяСсылка))

ИНДЕКСИРОВАТЬ ПО
	Регистратор,
	Контрагент,
	Магазин
;

ВЫБРАТЬ
	Акции.Регистратор КАК Регистратор,
	ЕСТЬNULL(ВТ_Получатели.Контрагент, ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)) КАК Контрагент
ИЗ
	РегистрСведений.Акции.СрезПоследних(&Период, ) КАК Акции
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Получатели КАК ВТ_Получатели
			ПО Акции.Регистратор = ВТ_Получатели.Регистратор

Такой подход обеспечивает предсказуемое поведение выборки, исключает влияние неоптимальных соединений и ускоряет выполнение запроса при больших объемах данных.

← На главную