Как быстро получить последнее движение по контрагентам в регистре бухгалтерии «Хозрасчетный» в 1С?

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

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

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

Анализ проблемы: почему типовые виртуальные таблицы работают медленно?

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

  1. Использование виртуальной таблицы ДвиженияССубконто: Данная виртуальная таблица предназначена для разворота субконто в отдельные колонки для каждой строки проводки. При обращении к ней СУБД строит тяжелые динамические соединения основной таблицы движений с таблицами субконто дебета и кредита. На больших периодах и объемах данных это приводит к колоссальным накладным расходам и сканированию всей таблицы.
  2. Использование виртуальной таблицы Обороты без жестких фильтров: Если мы берем таблицу оборотов без указания точного периода и конкретного счета, платформе приходится рассчитывать агрегаты по итогам и таблице движений, что также занимает значительное время.
  3. Соединение с вложенным подзапросом: Распространенной ошибкой является получение максимума периода через конструкцию ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ МАКСИМУМ(...) ИЗ ...). СУБД не может заранее рассчитать статистику по результату неиндексированного подзапроса и нередко выбирает худший план выполнения (например, вложенные циклы Nested Loops для сотен тысяч строк).

Физическая структура таблицы «Субконто»

Чтобы запрос отрабатывал за доли секунды, обратимся к физическому устройству регистра бухгалтерии в СУБД. В платформе 1С:Предприятие 8 таблица РегистрБухгалтерии.Хозрасчетный.Субконто является реальной (физической) таблицей базы данных. Она содержит следующие ключевые поля:

  1. Период — дата и время совершения проводки.
  2. Регистратор — ссылка на документ, сформировавший проводку.
  3. НомерСтроки — позиция проводки внутри документа.
  4. Вид — ссылка на вид субконто из плана видов характеристик (например, ВидыСубконтоХозрасчетные.Контрагенты).
  5. Значение — конкретное значение субконто (ссылка на элемент справочника Контрагенты).

Платформа автоматически строит по этой таблице кластерные и вторичные индексы вида (Вид, Значение, Период). Благодаря этому фильтрация по конкретному виду субконто и поиск максимальной даты по индексу выполняются СУБД мгновенно.

Пошаговый алгоритм быстрого среза последних

Разберем по шагам надежную схему формирования среза последних на языке запросов 1С:

  1. Подготовка списка контрагентов: Если требуется отобрать данные только по определенному кругу партнеров, помещаем их список во временную таблицу и обязательно индексируем поле ссылки.
  2. Поиск максимального периода: Обращаемся напрямую к физической таблице РегистрБухгалтерии.Хозрасчетный.Субконто, устанавливаем отбор по виду субконто, группируем по контрагенту и вычисляем функцию МАКСИМУМ(Период). Результат сохраняем во временную таблицу с индексацией по контрагенту и периоду.
  3. Разрешение коллизий и выбор регистратора: В реальной базе в одну секунду по одному контрагенту может быть проведено несколько документов. Если просто соединить контрагента и максимальную дату с движениями, мы получим дублирование строк. Чтобы гарантировать строго одну запись на каждого контрагента, берем МАКСИМУМ(Регистратор) на найденную максимальную дату.
  4. Итоговая выборка: Соединяем полученные данные с реквизитами документов или справочников.

Оптимальный текст запроса 1С

Рассмотрим пример готового пакетного запроса, который эффективно справляется с выборкой последних движений даже на базе со 100 000 контрагентов:


ВЫБРАТЬ
    Контрагенты.Ссылка КАК Контрагент
ПОМЕСТИТЬ втКонтрагенты
ИЗ
    Справочник.Контрагенты КАК Контрагенты
ГДЕ
    НЕ Контрагенты.ЭтоГруппа
    // При необходимости отбора по массиву:
    // И Контрагенты.Ссылка В (&СписокКонтрагентов)
ИНДЕКСИРОВАТЬ ПО
    Контрагент
;

////////////////////////////////////////////////////////////////////////////////
// Шаг 1: Находим максимальную дату движения по каждому контрагенту
ВЫБРАТЬ
    ТаблицаСубконто.Значение КАК Контрагент,
    МАКСИМУМ(ТаблицаСубконто.Период) КАК Период
ПОМЕСТИТЬ втМаксПериоды
ИЗ
    втКонтрагенты КАК втКонтрагенты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Субконто КАК ТаблицаСубконто
        ПО ТаблицаСубконто.Вид = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты)
        И втКонтрагенты.Контрагент = ТаблицаСубконто.Значение
СГРУППИРОВАТЬ ПО
    ТаблицаСубконто.Значение
ИНДЕКСИРОВАТЬ ПО
    Контрагент,
    Период
;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Получаем уникальный регистратор на максимальную дату
ВЫБРАТЬ
    втМаксПериоды.Контрагент КАК Контрагент,
    втМаксПериоды.Период КАК Период,
    МАКСИМУМ(ТаблицаСубконто.Регистратор) КАК Регистратор
ПОМЕСТИТЬ втИтоговыеДвижения
ИЗ
    втМаксПериоды КАК втМаксПериоды
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Субконто КАК ТаблицаСубконто
        ПО ТаблицаСубконто.Вид = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты)
        И втМаксПериоды.Контрагент = ТаблицаСубконто.Значение
        И втМаксПериоды.Период = ТаблицаСубконто.Период
СГРУППИРОВАТЬ ПО
    втМаксПериоды.Контрагент,
    втМаксПериоды.Период
ИНДЕКСИРОВАТЬ ПО
    Контрагент
;

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

Важные практические рекомендации

Для достижения максимальной скорости выполнения обратите внимание на следующие нюансы:

  1. Обязательная индексация полей соединения: Во временных таблицах всегда используйте предложение ИНДЕКСИРОВАТЬ ПО для полей, участвующих в связях ПО последующих запросов пакета. Это позволяет оптимизатору СУБД применять быстрые алгоритмы Merge Join или Index Seek.
  2. Отказ от вложенных соединений: Избегайте соединения таблицы с подзапросами в блоке ИЗ. Перенос промежуточных выборок во временные таблицы дает СУБД актуальную статистику распределения ключей.
  3. Порционная обработка (батчинг): Если требуется обработать свыше 200 000 контрагентов в условиях ограниченных ресурсов сервера tempdb, разбейте массив контрагентов на порции по 10 000 – 25 000 элементов и выполняйте запрос в цикле с выгрузкой во внешнюю таблицу значений.

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

← На главную