Как правильно и эффективно получить остатки по списку номенклатуры в регистре бухгалтерии

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

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

Анализ проблемы: Почему ЛЕВОЕ СОЕДИНЕНИЕ может работать медленно

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


// ТабНоменклатура - номенклатура для запроса остатков
ВЫБРАТЬ
    Таб0.Номенклатура
ПОМЕСТИТЬ ТабНоменклатура
ИЗ
    Таб0
СГРУППИРОВАТЬ ПО
    Таб0.Номенклатура;

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

Выясним причину неоптимальности: в данном случае виртуальная таблица Остатки сначала рассчитает данные по всем товарам на указанных складах и счетах, и только потом СУБД выполнит соединение с вашей временной таблицей. Если в справочнике 100 000 товаров, а вам нужно всего 1 000, система выполнит огромный объем лишней работы.

Перенос фильтра в параметры виртуальной таблицы

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

Для этого мы воспользуемся конструкцией В (ВЫБРАТЬ ... ИЗ ВТ) прямо во втором параметре (Условие) виртуальной таблицы. Рассмотрим исправленный код:


ВЫБРАТЬ
    Остатки.Субконто3.Код КАК СкладКод,
    Остатки.КоличествоОстаток КАК Остатки,
    Остатки.Субконто1.Код КАК НоменклатураКод
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Остатки(
        ,
        Счет В ИЕРАРХИИ (&ВыбСчет),
        ,
        Субконто1 В (ВЫБРАТЬ Т.Номенклатура ИЗ ТабНоменклатура КАК Т)
            И Субконто3 В (&Склады)
    ) КАК Остатки

Такой подход заставляет СУБД использовать индексы регистра по полям субконто, что в разы ускоряет выполнение запроса при больших объемах данных.

Оптимизация через использование «ВидыСубконто»

Одной из скрытых проблем регистра бухгалтерии является неопределенность порядка субконто. На одном счете "Номенклатура" может быть первым субконто, на другом — вторым. Если мы просто пишем Субконто1, запрос может отработать некорректно или медленно.

Рассмотрим решение: передачу третьего параметра виртуальной таблицы — ВидыСубконто. Мы создаем массив, содержащий ссылки на ПВХ ВидыСубконтоХозрасчетные.Номенклатура и ВидыСубконтоХозрасчетные.Склады.

При использовании этого параметра платформа жестко фиксирует, что Субконто1 — это номенклатура, а Субконто2 — склад (в соответствии с порядком в массиве), независимо от настроек конкретного счета. Это исключает лишние соединения с таблицами значений субконто на уровне SQL.

Важность индексирования временных таблиц

Когда мы используем временную таблицу в условии В (ВЫБРАТЬ...), крайне важно обеспечить быстрый поиск по ней. Если список номенклатуры содержит сотни или тысячи записей, обязательно добавьте индекс. Проанализируем пример создания проиндексированной ВТ:


ВЫБРАТЬ
    Таб0.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ТабНоменклатура
ИЗ
    &ИсходныеДанные КАК Таб0
СГРУППИРОВАТЬ ПО
    Таб0.Номенклатура

ИНДЕКСИРОВАТЬ ПО
    Номенклатура;

Без индекса СУБД может прибегнуть к сканированию всей временной таблицы для каждой строки основного запроса, что нивелирует всю выгоду от использования параметров виртуальной таблицы.

Приведение типов через ВЫРАЗИТЬ

Поля Субконто1, Субконто2 имеют составной тип данных. При обращении к свойствам этих полей (например, Субконто1.Код) в SQL-запросе создается множество соединений (JOIN) со всеми возможными таблицами справочников, входящих в этот тип.

Рекомендация: всегда используйте ВЫРАЗИТЬ. Это позволяет SQL-серверу обращаться напрямую к таблице конкретного справочника.


ВЫБРАТЬ
    ВЫРАЗИТЬ(Остатки.Субконто1 КАК Справочник.Номенклатура).Код КАК НоменклатураКод,
    ВЫРАЗИТЬ(Остатки.Субконто3 КАК Справочник.Склады).Код КАК СкладКод,
    Остатки.КоличествоОстаток КАК КоличествоОстаток
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Остатки(
        &Период,
        Счет В ИЕРАРХИИ (&ВыбСчет),
        &МассивВидовСубконто,
        Субконто1 В (ВЫБРАТЬ Т.Номенклатура ИЗ ТабНоменклатура КАК Т)
    ) КАК Остатки

Итоговый чек-лист идеального запроса к остаткам

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

  1. Используйте параметры виртуальной таблицы: Никогда не делайте фильтрацию по номенклатуре или складу в секции ГДЕ или через СОЕДИНЕНИЕ после получения всех остатков. Всегда передавайте условия во второй параметр виртуальной таблицы.
  2. Индексируйте ВТ: Если фильтр передается через временную таблицу, она должна быть проиндексирована по полю связи.
  3. Явно указывайте Виды Субконто: Это гарантирует правильное распределение полей СубконтоN и ускоряет работу SQL.
  4. Используйте типизацию: Применяйте ВЫРАЗИТЬ для полей субконто в итоговой выборке.
  5. Следите за порядком субконто: Если вы не используете 3-й параметр (ВидыСубконто), помните, что на разных счетах порядок субконто может отличаться. В таких случаях эффективнее разделять запросы для групп счетов с одинаковой структурой.

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

← На главную