Как лучше сравнивать две колонки одной таблицы в запросе 1С: через условие ГДЕ или конструкцию ВЫБОР?

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

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

Вариант №1: Прямое сравнение в условии ГДЕ

Рассмотрим самый простой и очевидный способ. Мы помещаем таблицу значений во временную таблицу и в этом же или следующем пакете запроса накладываем условие равенства двух полей. Это наиболее лаконичный вариант, который минимизирует объем кода и количество операций на стороне сервера.

Проанализируем пример кода, где фильтрация происходит непосредственно при обращении к данным:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	ТЗ.Номенклатура КАК Номенклатура,
|	ТЗ.Код1 КАК Код1,
|	ТЗ.Код2 КАК Код2
|ПОМЕСТИТЬ ВремТЗ
|ИЗ
|	&ТЗ КАК ТЗ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ВремТЗ.Номенклатура КАК Номенклатура,
|	ВремТЗ.Код1 КАК Код1
|ИЗ
|	ВремТЗ КАК ВремТЗ
|ГДЕ
|	ВремТЗ.Код1 = ВремТЗ.Код2";

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

  1. Минимальная нагрузка на TempDB: СУБД не нужно создавать дополнительные структуры данных для хранения промежуточных булевых флажков.
  2. Скорость выполнения: Оптимизатор СУБД (SQL Server, PostgreSQL) эффективно обрабатывает такие условия "на лету" во время сканирования таблицы.
  3. Читаемость: Код понятен любому разработчику и соответствует стандартам разработки 1С.

Вариант №2: Использование конструкции ВЫБОР и промежуточной таблицы

Некоторые разработчики предпочитают сначала вычислить результат сравнения, сохранить его в отдельное поле (например, типа Булево), поместить это во вторую временную таблицу и только потом фильтровать. Посмотрим, как это выглядит в коде:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	ТЗ.Номенклатура КАК Номенклатура,
|	ТЗ.Код1 КАК Код1,
|	ТЗ.Код2 КАК Код2,
|	ВЫБОР
|		КОГДА ТЗ.Код1 = ТЗ.Код2 ТОГДА ИСТИНА
|		ИНАЧЕ ЛОЖЬ
|	КОНЕЦ КАК Совпадают
|ПОМЕСТИТЬ ВремСРезультатом
|ИЗ
|	&ТЗ КАК ТЗ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ВремСРезультатом.Номенклатура,
|	ВремСРезультатом.Код1
|ИЗ
|	ВремСРезультатом КАК ВремСРезультатом
|ГДЕ
|	ВремСРезультатом.Совпадают = ИСТИНА";

Разберем ситуацию: этот метод является избыточным. Создание дополнительной временной таблицы ВремСРезультатом заставляет СУБД выполнять физическую запись данных в TempDB. Если ваша таблица содержит сотни тысяч строк, это приведет к заметному замедлению из-за дисковых операций ввода-вывода.

Важные технические нюансы и "подводные камни"

При сравнении полей в запросах 1С необходимо учитывать несколько критических факторов, которые могут повлиять на результат и скорость работы:

1. Проблема неопределенных значений (NULL)

Выясним причину, почему простое Код1 = Код2 может не сработать. В языке SQL результат любого сравнения с NULL дает Unknown, что для фильтра ГДЕ эквивалентно Ложь. Если в обеих колонках стоит NULL, они не будут признаны равными. Чтобы избежать этого, используйте функцию ЕСТЬNULL:

ГДЕ ЕСТЬNULL(ВремТЗ.Код1, 0) = ЕСТЬNULL(ВремТЗ.Код2, 0)

2. Индексация и производительность

Рассмотрим подробнее вопрос индексации. Запросы вида Поле1 = Поле2 называются не-SARGable. Это означает, что даже если вы построите индексы по обоим полям, СУБД все равно будет вынуждена выполнить полное сканирование таблицы (Table Scan), так как она не может заранее знать, какие значения совпадут. Поэтому использование дополнительных временных таблиц (Вариант №2) только усугубляет ситуацию, добавляя лишнюю фазу записи.

3. Использование внутренних соединений (Self-Join)

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

Рекомендации по выбору метода

На основе технического анализа и практического опыта можно сделать следующие выводы:

Таким образом, мы выяснили, что наиболее эффективным и правильным является прямое сравнение полей в секции ГДЕ при первом же обращении к временной таблице. Это избавляет систему от лишних записей в базу данных и делает код чище.

← На главную