Как правильнее сравнить две таблицы в запросе 1С: через объединение или соединение?

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

При разработке сложных алгоритмов обработки данных в 1С часто возникает задача сравнения двух наборов данных (таблиц). Это может быть сверка остатков между разными регистрами, поиск изменений при обмене данными или валидация результатов перед записью. Основной вопрос, который встает перед разработчиком: какой метод выбрать с точки зрения производительности и корректности результата? В этой статье мы подробно разберем два основных подхода, ориентируясь на быстрый анализ данных и способы упростить работу разработчика при написании запросов.

Постановка задачи и варианты решения

Представим, что у нас есть две таблицы с одинаковой структурой (назовем их Таблица А и Таблица Б). Нам необходимо выяснить, идентичны ли они, или же найти расхождения. Казалось бы, задача тривиальная, но дьявол кроется в деталях: как запрос поведет себя при наличии дублей? Как будут обрабатываться NULL значения? Какую нагрузку это создаст на СУБД?

Давайте проанализируем два основных метода, предложенных в профессиональном сообществе, и выясним их плюсы и минусы.

Метод 1: Сравнение через ОБЪЕДИНИТЬ ВСЕ (Рекомендуемый)

Этот метод часто называют "математическим" или методом симметричной разности. Суть его заключается в том, что мы не пытаемся соединить строки двух таблиц друг с другом, а сваливаем их в одну кучу, предварительно пометив принадлежность к источнику.

Разберем алгоритм по шагам:

  1. Выбираем все поля из Таблицы А и добавляем служебное поле-индикатор со значением 1.
  2. Выбираем все поля из Таблицы Б и добавляем служебное поле-индикатор со значением -1.
  3. Используем оператор ОБЪЕДИНИТЬ ВСЕ (Union All), чтобы получить единую таблицу.
  4. Группируем результат по всем полям сравнения, а поле-индикатор суммируем.
  5. Накладываем условие отбора (ИМЕЮЩИЕ): сумма индикатора не равна 0.

Посмотрим на пример кода запроса, реализующего этот алгоритм (отладить который поможет совместимая консоль запросов, подходящая для всех платформ 1С):


ВЫБРАТЬ
    Т1.Номенклатура КАК Номенклатура,
    Т1.Количество КАК Количество,
    1 КАК Индикатор
ПОМЕСТИТЬ ВТ_Объединение
ИЗ
    ТаблицаА КАК Т1

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

ВЫБРАТЬ
    Т2.Номенклатура,
    Т2.Количество,
    -1
ИЗ
    ТаблицаБ КАК Т2
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Объединение.Номенклатура,
    ВТ_Объединение.Количество,
    СУММА(ВТ_Объединение.Индикатор) КАК Разница
ИЗ
    ВТ_Объединение КАК ВТ_Объединение

СГРУППИРОВАТЬ ПО
    ВТ_Объединение.Номенклатура,
    ВТ_Объединение.Количество

ИМЕЮЩИЕ
    СУММА(ВТ_Объединение.Индикатор) <> 0

Преимущества этого метода:

  1. Корректная работа с дублями: Если в Таблице А запись встречается 2 раза, а в Таблице Б — 1 раз, сумма индикаторов будет равна 2 + (-1) = 1. Условие <> 0 сработает, и мы увидим разницу. Многие другие методы пропустят этот момент.
  2. Устойчивость к NULL: При группировке платформа 1С и SQL-сервер сворачивают NULL значения в одну группу. Вам не нужно писать громоздкие конструкции ЕСТЬNULL для каждого поля.
  3. Производительность: С точки зрения плана выполнения запроса (Query Plan), ОБЪЕДИНИТЬ ВСЕ часто выигрывает у ПОЛНОГО СОЕДИНЕНИЯ. Учитывая общую производительность способов обхода таблицы значений по группировке, этот метод чаще всего использует Index Scan или Sort. Это линейные операции, которые часто быстрее сложных алгоритмов соединения.

Метод 2: Сравнение через ПОЛНОЕ СОЕДИНЕНИЕ

Второй популярный подход — попытаться "склеить" таблицы по всем полям. Логика следующая: если запись есть в обеих таблицах, они соединятся. Если записи нет в одной из таблиц, мы получим NULL с одной стороны.

Для поиска различий мы должны выбрать записи, где есть NULL хотя бы с одной стороны.

Разберем пример кода:


ВЫБРАТЬ
    ЕСТЬNULL(Т1.Номенклатура, Т2.Номенклатура) КАК Номенклатура,
    ЕСТЬNULL(Т1.Количество, Т2.Количество) КАК Количество
ИЗ
    ТаблицаА КАК Т1
        ПОЛНОЕ СОЕДИНЕНИЕ ТаблицаБ КАК Т2
        ПО Т1.Номенклатура = Т2.Номенклатура
        И Т1.Количество = Т2.Количество
ГДЕ
    (Т1.Номенклатура ЕСТЬ NULL
    ИЛИ Т2.Номенклатура ЕСТЬ NULL)

Недостатки и подводные камни этого метода:

Давайте проанализируем критические уязвимости этого подхода, о которых нужно знать.

Проблема 1: Сравнение с NULL.
В языке запросов NULL = NULL дает результат FALSE. Если в ваших данных могут быть пустые значения, ПОЛНОЕ СОЕДИНЕНИЕ не сможет сопоставить такие строки. Они выпадут в результат как различные, хотя по факту они одинаковы. Чтобы этого избежать, рекомендуем изучить руководство по обработке пустых значений.

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

Когда использовать хеширование?

Бывают ситуации, когда таблицы очень "широкие". Сравнивать их по каждому полю через ОБЪЕДИНИТЬ ВСЕ накладно для процессора СУБД. Чтобы оптимизировать процесс, полезна проверка запросов на лишнюю выборку и полей во временных таблицах.

В этом случае эффективным решением будет предварительный расчет хеш-суммы строки:

  1. Перед помещением данных в запрос (или во вложенном запросе), вы добавляете поле ХешСтроки.
  2. Сравнение в запросе производится только по одному полю — этому хешу.

Это радикально снижает нагрузку на операции сравнения строк, так как сравниваются не сотни байт, а короткие строки или числа.

Вопрос производительности: Запрос или код 1С?

В обсуждении была затронута важная тема: всегда ли нужно использовать запрос? Если объем данных невелик, накладные расходы на временные таблицы могут превысить время самого сравнения. Однако когда на запрос накладывается множество условий и производительность падает, иногда применяется циклическая вложенная фильтрация.

Для "микрообъемов" (до 1000 строк) можно использовать методы встроенного языка 1С:

  1. КоллекцииИдентичны (БСП): функция из общего модуля ОбщегоНазначения.
  2. Сортировка + Линейный проход:
    
    Таблица1.Сортировать("Номенклатура, Количество");
    Таблица2.Сортировать("Номенклатура, Количество");
    // Далее один цикл по индексам для сравнения строк
    

Итоговые рекомендации

Подводя итог нашему анализу, сформулируем правила выбора инструмента:

  1. Если ваша цель — найти расхождения и таблицы могут содержать дубли или NULL — используйте Метод 1 (ОБЪЕДИНИТЬ ВСЕ + СГРУППИРОВАТЬ). Это самый надежный и универсальный способ.
  2. Если вам нужно просто получить ответ "Да/Нет" и вы уверены в уникальности записей — можно использовать ПОЛНОЕ СОЕДИНЕНИЕ с выбором ПЕРВЫЕ 1.
  3. Если количество строк невелико (до пары тысяч), не усложняйте систему запросами — выполните сравнение в памяти сервера приложений 1С.
← На главную