При работе с запросами в системе 1С:Предприятие часто возникает задача, когда нужно собрать данные из одного регистра, но наложить условия фильтрации, зависящие от наличия записей в другом регистре. Ситуация осложняется, когда в одном регистре присутствуют документы разных типов, и правила фильтрации для них различаются. Рассмотрим, как эффективно решить эту задачу, избежав типичных ошибок производительности.
Представим ситуацию: у нас есть два регистра накопления — Продажи и РасчетыСПокупателями. В регистре Продажи фиксируются движения по документам РеализацияТоваровУслуг и ОтчетОРозничныхПродажах. В регистре РасчетыСПокупателями отражаются только Реализации. Нам необходимо получить итоговую таблицу, в которую войдут:
ОтчетОРозничныхПродажах из регистра Продажи.РеализацияТоваровУслуг из регистра Продажи, которые также присутствуют в регистре РасчетыСПокупателями.Разберем по шагам, почему классическое ЛЕВОЕ СОЕДИНЕНИЕ здесь может быть не лучшим выбором и как правильно составить запрос.
Проанализируем подход, который является наиболее стабильным с точки зрения логики и производительности. Вместо того чтобы пытаться построить одно сложное соединение с условиями ИЛИ в блоке ГДЕ, мы разделим задачу на части и объединим результаты.
Рассмотрим пример кода запроса, который реализует эту логику:
ВЫБРАТЬ
Продажи.Регистратор КАК Регистратор,
Продажи.СуммаОборот КАК Сумма
ИЗ
РегистрНакопления.Продажи.Обороты КАК Продажи
ГДЕ
Продажи.Регистратор ССЫЛКА Документ.ОтчетОРозничныхПродажах
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Продажи.Регистратор,
Продажи.СуммаОборот
ИЗ
РегистрНакопления.Продажи.Обороты КАК Продажи
ГДЕ
Продажи.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
И Продажи.Регистратор В (
ВЫБРАТЬ РАЗЛИЧНЫЕ
Расчеты.Регистратор
ИЗ
РегистрНакопления.РасчетыСПокупателями КАК Расчеты
)
В первой части запроса мы выбираем все Отчеты о розничных продажах. Во второй части мы выбираем только те Реализации, которые входят в список регистраторов регистра РасчетыСПокупателями. Использование оператора ОБЪЕДИНИТЬ ВСЕ позволяет СУБД выполнить два простых поиска вместо одного сложного соединения, что положительно сказывается на скорости выполнения.
Профессиональная разработка в 1С подразумевает минимизацию вложенных запросов. Посмотрим, как переписать это решение с использованием временных таблиц. Это особенно важно, если регистры содержат сотни тысяч записей.
Проанализируем структуру такого запроса:
// Шаг 1: Собираем список нужных реализаций
ВЫБРАТЬ РАЗЛИЧНЫЕ
Расчеты.Регистратор КАК Документ
ПОМЕСТИТЬ ВТ_РеализацииВРасчетах
ИЗ
РегистрНакопления.РасчетыСПокупателями КАК Расчеты
ИНДЕКСИРОВАТЬ ПО
Документ;
// Шаг 2: Получаем итоговый результат
ВЫБРАТЬ
Продажи.Регистратор
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Регистратор ССЫЛКА Документ.ОтчетОРозничныхПродажах
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Продажи.Регистратор
ИЗ
РегистрНакопления.Продажи КАК Продажи
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_РеализацииВРасчетах КАК ВТ_Реализации
ПО Продажи.Регистратор = ВТ_Реализации.Документ
Выясним причину, по которой опытные разработчики предостерегают от прямых соединений физических таблиц разных регистров. Когда вы соединяете две таблицы по полю Регистратор, СУБД приходится сравнивать значения составных типов. Если в условии соединения или фильтрации появляется ИЛИ (например, ГДЕ Тип = Отчет ИЛИ (Тип = Реализация И НаличиеВРасчетах)), оптимизатор запросов SQL может отказаться от использования индексов и перейти к полному сканированию таблиц (Table Scan). Это приведет к тому, что отчет, который должен формироваться секунды, будет работать минуты.
При решении подобных задач важно помнить о следующих моментах:
.Обороты). Обращение к основной таблице регистра (физической) оправдано только тогда, когда вам нужны конкретные записи или значения реквизитов движений.Регистратор индексировано по умолчанию. Однако при использовании временных таблиц не забывайте добавлять инструкцию ИНДЕКСИРОВАТЬ ПО, чтобы ускорить последующее соединение.ОБЪЕДИНИТЬ ВСЕ следите за тем, чтобы колонки имели одинаковый порядок и совместимые типы данных.РасчетыСПокупателями один документ делает несколько записей, обычное ЛЕВОЕ СОЕДИНЕНИЕ может «размножить» строки из Продаж. Использование ВЫБРАТЬ РАЗЛИЧНЫЕ или временной таблицы с уникальными ссылками решает эту проблему.Таким образом, разделение сложной логики на простые блоки через временные таблицы и объединения — это залог надежного и быстрого кода в 1С.