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

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

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

Исходная ситуация и анализ «плохого» запроса

Разберем типичный пример запроса, который часто предлагается на экзаменах «1С:Специалист» или «1С:Эксперт»:


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

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

Ошибка №1: Прямое соединение физической таблицы с виртуальной

С точки зрения стандартов разработки 1С и механизмов работы СУБД (SQL Server, PostgreSQL), соединение физической таблицы (табличной части документа) напрямую с виртуальной таблицей (Остатки) является критической ошибкой. Рассмотрим почему:

  1. Неоптимальный план запроса: Когда мы пишем ЛЕВОЕ СОЕДИНЕНИЕ с виртуальной таблицей без параметров, СУБД сначала может попытаться рассчитать остатки по всем записям регистра, а уже потом соединить этот гигантский результат с одной строкой документа. Фильтр ГДЕ может быть наложен слишком поздно.
  2. Блокировки: Нагрузка на таблицы итогов возрастает в разы, что в высоконагруженных системах приводит к избыточным ожиданиям на блокировках.
  3. Отсутствие индексов: При динамическом расчете виртуальной таблицы СУБД не всегда может эффективно использовать индексы для связи с физической таблицей документа.

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

Ошибка №2: Проблема граничного момента времени

Обратим внимание на параметр &ДатаДокумента. В 1С использование простой даты в запросе к остаткам означает получение данных на начало этой даты (на 00:00:00), либо, если передана полная дата со временем, на начало соответствующей секунды.

Разберем ситуацию: Если документ уже проведен и мы хотим проверить остатки в момент его проведения, передача просто Дата приведет к тому, что остатки будут получены до движений текущего документа. Если в документе 10 единиц товара, и на складе было 10, запрос покажет наличие товара, даже если документ его уже списал. Для корректной работы необходимо использовать объект Граница или МоментВремени.

Правильное решение: Использование временных таблиц и параметров

Для исправления «глобальной ошибки» нам нужно перестроить запрос в пакетный режим. Рассмотрим поэтапно, как это сделать правильно.

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


ВЫБРАТЬ
    Док.Номенклатура КАК Номенклатура,
    Док.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
    Док.Склад КАК Склад
ПОМЕСТИТЬ ВТ_ТоварыДокумента
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК Док
ГДЕ
    Док.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
    Док.Номенклатура,
    Док.ХарактеристикаНоменклатуры,
    Док.Склад
ИНДЕКСИРОВАТЬ ПО
    Номенклатура,
    ХарактеристикаНоменклатуры,
    Склад;

Шаг 2: Получение остатков с фильтрацией. Теперь мы выбираем данные из виртуальной таблицы, передавая в параметры условие по нашей временной таблице. Это заставляет СУБД рассчитывать остатки только по нужным позициям.


ВЫБРАТЬ
    ВТ.Склад,
    ВТ.Номенклатура,
    ВТ.ХарактеристикаНоменклатуры,
    ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
ИЗ
    ВТ_ТоварыДокумента КАК ВТ
ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрНакопления.ТоварыНаСкладах.Остатки(
        &Период, 
        (Номенклатура, ХарактеристикаНоменклатуры, Склад) В 
            (ВЫБРАТЬ Номенклатура, ХарактеристикаНоменклатуры, Склад ИЗ ВТ_ТоварыДокумента)
    ) КАК ТоварыНаСкладахОстатки
ПО 
    ВТ.Номенклатура = ТоварыНаСкладахОстатки.Номенклатура
    И ВТ.ХарактеристикаНоменклатуры = ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры
    И ВТ.Склад = ТоварыНаСкладахОстатки.Склад

Почему это работает быстрее?

Проанализируем преимущества такого подхода. Во-первых, использование оператора В (ВЫБРАТЬ...) в параметрах виртуальной таблицы позволяет платформе 1С оптимизировать SQL-запрос, передавая список значений в качестве временной таблицы в SQL. Во-вторых, мы гарантируем, что виртуальная таблица не будет пересчитывать лишние данные.

Важный момент, который обсуждался на форуме: файловая база против клиент-серверной. В файловой базе создание временных таблиц имеет накладные расходы, которые могут сделать «правильный» запрос чуть медленнее на малых объемах. Однако в профессиональной разработке ориентироваться нужно на клиент-серверную архитектуру (SQL), где прямой JOIN физической и виртуальной таблиц — это прямой путь к деградации производительности всей системы.

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

Подводя итог, выясним, что именно считается «глобальной ошибкой» в данном контексте:

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

← На главную