Как правильно соединить временную таблицу со справочником и оптимизировать запрос к регистру сведений?

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

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

Основы соединения временной таблицы со справочником

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


// Первый запрос пакета: подготавливаем данные
ВЫБРАТЬ ПЕРВЫЕ 1000
    Автомобили.Ссылка КАК Автомобиль
ПОМЕСТИТЬ Вт_НужныеАвто
ИЗ
    Справочник.Автомобили КАК Автомобили;

////////////////////////////////////////////////////////////////////////////////
// Второй запрос пакета: соединение
ВЫБРАТЬ
    Вт_НужныеАвто.Автомобиль КАК Автомобиль,
    Регистр.Значение КАК ГосНомер
ИЗ
    Вт_НужныеАвто КАК Вт_НужныеАвто
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Автомобили.СрезПоследних(&Период, ) КАК Регистр
        ПО Вт_НужныеАвто.Автомобиль = Регистр.Автомобиль

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

Оптимизация виртуальных таблиц через параметры

Проанализируем распространенную ошибку: получение «Среза последних» по всему регистру с последующим соединением. Если в регистре сотни тысяч записей, система сначала рассчитает срез для всех строк, а потом отсечет лишние. Это крайне неэффективно. Правильный подход — передать фильтр непосредственно в параметры виртуальной таблицы.

Выясним причину, почему это работает быстрее: когда условие передается в параметры (в поле «Условие»), СУБД ограничивает выборку данных еще до момента расчета итогов среза. Рассмотрим пример оптимизированного запроса:


ВЫБРАТЬ
    Вт_НужныеАвто.Автомобиль КАК Автомобиль,
    СрезГосНомер.Значение КАК ГосНомер
ИЗ
    Вт_НужныеАвто КАК Вт_НужныеАвто
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Автомобили.СрезПоследних(&Период, 
            Автомобиль В (ВЫБРАТЬ Вт.Автомобиль ИЗ Вт_НужныеАвто КАК Вт)
            И ВидЗначения = ЗНАЧЕНИЕ(Перечисление.ДополнительнаяИнформацияАвтомобилей.ГосНомер)
        ) КАК СрезГосНомер
        ПО Вт_НужныеАвто.Автомобиль = СрезГосНомер.Автомобиль

В данном случае условие Автомобиль В (ВЫБРАТЬ...) внутри параметров СрезПоследних заставляет систему работать только с нужным подмножеством данных.

Важность условий в секции ПО против ГДЕ

Разберем критическую ошибку, упомянутую в обсуждении. При использовании ЛЕВОЕ СОЕДИНЕНИЕ любые условия на ПРАВУЮ таблицу (в нашем случае — регистр) должны располагаться строго в блоке ПО (условие связи), а не в блоке ГДЕ.

Проанализируем ситуацию: если мы напишем условие ГДЕ СрезГосНомер.Значение <> "", то наше «Левое соединение» превратится во «Внутреннее». Это происходит потому, что для тех строк, где связи не нашлось, значения полей будут NULL, а проверка NULL <> "" отсечет эти строки из результата. Если ваша задача — сохранить все записи из левой таблицы, пишите условия фильтрации регистра в секции ПО.

Индексирование временных таблиц

Для ускорения соединения таблиц, особенно когда во временной таблице содержится более нескольких сотен записей, необходимо использовать индексирование. Посмотрим на пример кода с индексом:


ВЫБРАТЬ
    Автомобили.Ссылка КАК Автомобиль
ПОМЕСТИТЬ Вт_НужныеАвто
ИЗ
    Справочник.Автомобили КАК Автомобили
ИНДЕКСИРОВАТЬ ПО
    Автомобиль;

Индекс позволяет СУБД мгновенно находить соответствия при выполнении JOIN, что предотвращает полное сканирование таблиц (Table Scan).

Метод разворота (Pivot) для получения нескольких характеристик

Часто требуется получить сразу несколько характеристик (Хозяин, Госномер, Пробег). Вместо того чтобы делать три тяжелых соединения с одним и тем же регистром, рассмотрим метод «разворота» через группировку. Это позволяет прочитать данные регистра всего один раз.


ВЫБРАТЬ
    Вт.Автомобиль КАК Автомобиль,
    МАКСИМУМ(ВЫБОР КОГДА Срез.ВидЗначения = &ВидХозяин ТОГДА Срез.Значение КОНЕЦ) КАК Хозяин,
    МАКСИМУМ(ВЫБОР КОГДА Срез.ВидЗначения = &ВидГосНомер ТОГДА Срез.Значение КОНЕЦ) КАК ГосНомер,
    МАКСИМУМ(ВЫБОР КОГДА Срез.ВидЗначения = &ВидПробег ТОГДА Срез.Значение КОНЕЦ) КАК Пробег
ИЗ
    Вт_НужныеАвто КАК Вт
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Автомобили.СрезПоследних(&Период, 
            Автомобиль В (ВЫБРАТЬ Вт.Автомобиль ИЗ Вт_НужныеАвто КАК Вт)
        ) КАК Срез
        ПО Вт.Автомобиль = Срез.Автомобиль
СГРУППИРОВАТЬ ПО
    Вт.Автомобиль

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

Проблема использования ПЕРВЫЕ без сортировки

В сообщениях форума автор жаловался на «пустые поля» при использовании ПЕРВЫЕ 1000. Выясним причину: в 1С (как и в SQL) выборка первых записей без использования УПОРЯДОЧИТЬ ПО является недетерминированной. Это означает, что система берет первые попавшиеся записи из физической таблицы. В начало списка могут попасть новые элементы справочника, по которым в регистре еще нет данных.

Рекомендация: всегда используйте УПОРЯДОЧИТЬ ПО вместе с ПЕРВЫЕ, чтобы результат был предсказуемым. Например, по коду или ссылке автомобиля.

Использование механизма Характеристик в СКД

Если задача стоит в рамках построения отчета, разберем альтернативный вариант — использование Системы компоновки данных (СКД). В СКД существует встроенный механизм работы с характеристиками. Настроив вкладку «Характеристики» в наборе данных, вы позволите пользователю выбирать поля «Госномер» или «Пробег» так, будто это реквизиты самого справочника. При этом 1С сама сформирует оптимальный SQL-запрос с учетом всех правил индексации и связей.

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

← На главную