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

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

В практике разработчика 1С часто возникает задача поиска объектов (документов или справочников), состав табличной части которых в точности соответствует переданному образцу. Типичный пример: найти заказ клиента с точно таким же перечнем товаров и количеств, как в текущей корзине. При малых объемах данных любое решение будет работать быстро, но когда речь идет о десятках тысяч документов, неоптимальные запросы начинают «тормозить» систему. Разберем, как реализовать этот поиск максимально эффективно.

Анализ проблемы и неэффективных подходов

Рассмотрим ситуацию, с которой столкнулся автор темы. Изначально задача решалась через полное соединение (FULL JOIN) или даже через декартово произведение (CROSS JOIN) с последующей фильтрацией. Проанализируем, почему это плохой путь.

Использование конструкции ПО (ИСТИНА) в левом соединении приводит к тому, что система пытается перемножить каждую строку образца с каждой строкой из всей таблицы справочника или документа. На больших объемах это вызывает катастрофическое падение производительности. Рассмотрим пример неэффективного кода, который часто пытаются использовать новички:


// Пример неоптимального подхода через CROSS JOIN
Запрос.Текст = 
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|   втТаблицаБригады.Специалист,
|   БригадыСпециалисты.Ссылка КАК Ссылка1
|ПОМЕСТИТЬ втУмножение
|ИЗ
|   втТаблицаБригады КАК втТаблицаБригады
|   ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Бригады.Специалисты КАК БригадыСпециалисты
|   ПО (ИСТИНА);";

Такой подход заставляет сервер СУБД обрабатывать гигантские массивы временных данных. Правильный путь — использовать логику реляционного деления, основанную на сравнении количеств и состава строк.

Решение 1: Метод сравнения по количеству и составу (оптимальный)

Давайте разберем наиболее надежный и быстрый алгоритм. Его суть заключается в следующем: если в документе-кандидате количество строк совпадает с количеством строк в образце, и при этом все строки образца присутствуют в этом документе, то такие наборы идентичны.

Выполним задачу по шагам:

  1. Подготовка образца: Поместим исходную таблицу (ТЗ) во временную таблицу, обязательно проиндексировав ключевые поля.
  2. Подсчет строк в образце: Вычислим, сколько всего строк в нашем эталоне.
  3. Внутреннее соединение: Соединим таблицу-эталон с табличной частью документов по всем значимым полям (например, Номенклатура и Количество).
  4. Группировка и фильтрация: Сгруппируем результат по ссылке на документ и оставим только те документы, где количество совпавших строк равно количеству строк в эталоне, и общее количество строк в самом документе также равно этому числу.

Проанализируем пример реализации такого запроса:


// 1. Помещаем образец в ВТ и считаем количество строк
"ВЫБРАТЬ
|   Образец.Номенклатура КАК Номенклатура,
|   Образец.Количество КАК Количество
|ПОМЕСТИТЬ втОбразец
|ИЗ
|   &ТаблицаОбразец КАК Образец
|ИНДЕКСИРОВАТЬ ПО
|   Номенклатура,
|   Количество;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|   КОЛИЧЕСТВО(*) КАК ВсегоСтрок
|ПОМЕСТИТЬ втПараметры
|ИЗ
|   втОбразец КАК втОбразец;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|   ТЧ.Ссылка
|ИЗ
|   Документ.РеализацияТоваровУслуг.Товары КАК ТЧ
|   ВНУТРЕННЕЕ СОЕДИНЕНИЕ втОбразец КАК втОбразец
|   ПО ТЧ.Номенклатура = втОбразец.Номенклатура
|       И ТЧ.Количество = втОбразец.Количество
|ГДЕ
|   ТЧ.Ссылка.Проведен // Дополнительный фильтр для ускорения
|СГРУППИРОВАТЬ ПО
|   ТЧ.Ссылка
|ИМЕЯ
|   КОЛИЧЕСТВО(ТЧ.Номенклатура) = (ВЫБРАТЬ ВсегоСтрок ИЗ втПараметры)
|   И КОЛИЧЕСТВО(ТЧ.Ссылка.Товары.НомерСтроки) = (ВЫБРАТЬ ВсегоСтрок ИЗ втПараметры)";

Важный нюанс: Условие в ИМЕЯ (HAVING) по количеству строк в самом документе (КОЛИЧЕСТВО(ТЧ.Ссылка.Товары.НомерСтроки)) критически важно. Без него запрос найдет и те документы, где наш образец является лишь частью (подмножеством) более крупного списка товаров.

Решение 2: Обработка дублей и агрегация

Выясним причину возможных ошибок при наличии одинаковых строк в ТЧ. Если в документе или в образце может быть две строки с одной и той же номенклатурой и одинаковым количеством, прямое соединение «размножит» записи, и результат КОЛИЧЕСТВО() будет неверным.

Чтобы избежать этого, перед сравнением мы должны свернуть (сгруппировать) обе таблицы. Рассмотрим, как это изменить в запросе:


// Сворачиваем данные ТЧ документа перед сравнением
"ВЫБРАТЬ
|   ТЧ.Ссылка КАК Ссылка,
|   ТЧ.Номенклатура КАК Номенклатура,
|   СУММА(ТЧ.Количество) КАК Количество
|ПОМЕСТИТЬ втСвернутаяТЧ
|ИЗ
|   Документ.Продажа.Товары КАК ТЧ
|СГРУППИРОВАТЬ ПО
|   ТЧ.Ссылка,
|   ТЧ.Номенклатура;";

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

Решение 3: Метод контрольных сумм (для сверхбольших данных)

Проанализируем ситуацию, когда документов миллионы, а поиск нужно выполнять мгновенно. В этом случае соединение «лоб в лоб» может быть накладным. Опытные разработчики применяют технику хеширования или контрольных сумм.

Для каждой строки ТЧ можно вычислить числовой идентификатор. Например, ХешСтроки = (ВнутреннийКодНоменклатуры * Количество). Затем для каждого документа в отдельном регистре или реквизите шапки хранится СуммарныйХеш (сумма хешей всех строк). При поиске мы сначала отбираем документы, у которых СуммарныйХеш совпадает с хешем нашего образца. Это позволяет мгновенно отсечь 99.9% неподходящих документов, а оставшиеся единицы проверить детально методом из первого решения.

Основные рекомендации по оптимизации

Подведем итог и выделим ключевые правила для эффективной работы запроса:

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

← На главную