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