Как правильно выбрать проводки по возвратной таре в 1С без зависаний СУБД

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

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

Анализ исходной проблемы

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

Первая попытка автора темы заключалась в левом соединении табличной части документа РеализацияТоваровУслуг.ВозвратнаяТара с виртуальной таблицей РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто по полю Регистратор с последующим наложением фильтра по счету дебета в секции ГДЕ. Этот подход привел к тому, что в выборку попала абсолютно вся тара из документов, даже та, по которой не было соответствующих проводок. Попытка исправить ситуацию и вытащить субконто привела к полному зависанию системы.

Выясним причины такого поведения платформы 1С и СУБД:

  1. Левое соединение с виртуальной таблицей без параметров. Когда мы связываем физическую таблицу документов с виртуальной таблицей движений регистра без указания параметров (периода, счетов, фильтров) внутри самой виртуальной таблицы, СУБД сначала пытается прочитать и поднять в оперативную память абсолютно все записи регистра бухгалтерии с самого начала ведения учета. Только после этого происходит наложение связи и фильтрация в секции ГДЕ. Это классическая причина зависаний.
  2. Фильтрация по счету в предложении ГДЕ вместо параметров виртуальной таблицы. Конструкция ГДЕ ХозрасчетныйДвиженияССубконто.СчетДт = &Счет заставляет базу данных выполнять избыточную работу, считывая лишние данные по всем остальным счетам, прежде чем отсечь их на финальном этапе выполнения запроса.

Разбор "работающего", но опасного решения

В ходе обсуждения на форуме автор пришел к промежуточному решению, которое "заработало" на небольшом объеме данных:


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

Хотя этот запрос вернул результат, он содержит три критические архитектурные ошибки, которые обязательно "выстрелят" при увеличении базы данных или при запуске в многопользовательском режиме.

Ошибка 1: Обращение через точку к составному типу данных (Разыменование)

Поле Регистратор в регистре бухгалтерии имеет составной тип. Оно может ссылаться на десятки различных видов документов (Реализация, Отчет о розничных продажах, ОперацияБух и т.д.). Конструкция ХозрасчетныйДвиженияССубконто.Регистратор.Контрагент заставляет платформу на уровне СУБД генерировать неявные левые соединения (LEFT JOIN) со всеми таблицами документов, у которых физически может быть реквизит Контрагент. Функция ВЫРАЗИТЬ для результата не спасает от этих соединений. В итоге SQL-запрос превращается в огромную "простыню" соединений, нагружающую процессор сервера СУБД.

Ошибка 2: Отсутствие отбора по счету в параметрах виртуальной таблицы

Условие по счету дебета по-прежнему находится в секции ГДЕ. СУБД вынуждена анализировать все проводки за период по экспедитору, а не только проводки по счету 73.03.

Ошибка 3: Пропуск проверки активности записей

Виртуальная таблица ДвиженияССубконто выбирает в том числе неактивные движения (например, движения по распроведенным документам или помеченным на удаление, если они физически остались в базе). Без явного указания фильтра по активности отчет может вывести некорректные "фантомные" данные.

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

Для решения этой задачи применим самый надежный и быстрый паттерн проектирования запросов в 1С — пакетный запрос с использованием индексированных временных таблиц.

Разобьем решение на два последовательных шага:

Шаг 1. Выборка документов. Сначала мы обратимся к физической таблице документов Документ.РеализацияТоваровУслуг, быстро отфильтруем нужные нам документы по периоду, контрагенту и экспедитору, после чего поместим их ссылки во временную таблицу и проиндексируем ее.

Шаг 2. Выборка из регистра бухгалтерии. Во втором запросе пакета мы обратимся к виртуальной таблице регистра бухгалтерии, передав все необходимые фильтры (включая массив отобранных документов и конкретный счет дебета) непосредственно в параметры этой виртуальной таблицы.

Посмотрим на пример реализации такого оптимального запроса:


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

ИНДЕКСИРОВАТЬ ПО
	Ссылка
;

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

Почему этот вариант работает быстрее всего?

Проанализируем преимущества предложенной схемы:

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

← На главную