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

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

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

Способ 1: Прямое обращение через точку (неявное соединение)

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


ВЫБРАТЬ
    Инвентаризация.Ссылка.Склад КАК Склад,
    Инвентаризация.Номенклатура КАК Номенклатура,
    Инвентаризация.Количество КАК Количество,
    Инвентаризация.КоличествоОстаток КАК КоличествоОстаток,
    Инвентаризация.Цена КАК Цена
ИЗ
    Документ.Инвентаризация.Товары КАК Инвентаризация
ГДЕ
    Инвентаризация.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И Инвентаризация.Ссылка.ВидОперации = &ВыбВид
УПОРЯДОЧИТЬ ПО
    Склад

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

Способ 2: Использование явного внутреннего соединения

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

Разберем по шагам создание такого запроса:

  1. Выбираем целевую табличную часть документа.
  2. Соединяем её с таблицей шапки документа по полю Ссылка.
  3. Накладываем условия на поля шапки документа.

ВЫБРАТЬ
    ДокШапка.Склад КАК Склад,
    ДокТовары.Номенклатура,
    ДокТовары.Количество,
    ДокТовары.Цена
ИЗ
    Документ.Инвентаризация.Товары КАК ДокТовары
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Инвентаризация КАК ДокШапка
    ПО ДокТовары.Ссылка = ДокШапка.Ссылка
ГДЕ
    ДокШапка.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И ДокШапка.ВидОперации = &ВыбВид
УПОРЯДОЧИТЬ ПО
    Склад

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

Способ 3: Оптимизация через временные таблицы (лучшая практика)

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

Сначала мы выберем только ссылки на документы, подходящие под наши условия, во временную таблицу, а затем соединим её с табличной частью:


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

////////////////////////////////////////////////////////////////////////////////
// Выбираем данные из табличной части, используя подготовленный список ссылок
ВЫБРАТЬ
    ВТ.Склад,
    Товары.Номенклатура,
    Товары.Количество,
    Товары.Цена
ИЗ
    ВТ_Документы КАК ВТ
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Инвентаризация.Товары КАК Товары
    ПО ВТ.Ссылка = Товары.Ссылка

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

Способ 4: Получение данных из регистров

В сообщении форума справедливо отмечено, что если целью является построение отчета, то тянуть данные напрямую из документов — не всегда верное архитектурное решение. Рассмотрим подробнее, когда стоит использовать регистры:

Однако стоит учитывать специфику: в некоторых конфигурациях (например, 1С:ERP или КА 2) документ "Инвентаризация товаров" сам по себе не делает движений по регистрам остатков, а является лишь основанием для документов "Списание недостач" или "Оприходование излишков". В таком случае обращение к табличной части документа — единственный способ получить данные о "плановых" показателях инвентаризации.

Важные нюансы и советы

При работе с запросами к табличным частям обратите внимание на следующие моменты:

  1. Индексация: Проверьте в конфигураторе, стоит ли свойство "Индексировать" у реквизита Склад в шапке документа. Если по этому полю часто выполняются отборы или сортировки, индексация существенно ускорит запросы.
  2. Поле КоличествоОстаток: Будьте внимательны с этим полем. В большинстве типовых решений это реквизит табличной части, который заполняется в момент нажатия кнопки "Заполнить по остаткам" в документе. Эти данные являются "застывшими" на момент создания документа. Если вам нужны реальные остатки на текущий момент, используйте регистры накопления.
  3. Вид операции: Если отбор идет по перечислению (ВидОперации), это работает быстро. Если же ВидОперации — это справочник, убедитесь, что он заполнен корректно во всех документах выборки.

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

← На главную