Задачи получения остатков на каждый день периода часто встречаются при построении аналитической отчетности, графиков продаж и систем планирования запасов. Однако при неправильном составлении запроса его выполнение может занимать недопустимо много времени или вызывать критическую нагрузку на сервер СУБД. Разберем основные ошибки в подобных запросах и рассмотрим способы их эффективной оптимизации.
Проанализируем типовую ситуацию, когда запрос формирует остатки на каждый день с помощью перемножения таблицы дат и виртуальной таблицы регистра РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты.
Выясним главные узкие места, создающие высокую нагрузку:
Движения.Номенклатура.ЕдиницаХраненияОстатков.Литраж заставляют СУБД делать неявные левые соединения (LEFT JOIN) с таблицами справочников для каждой выбранной строки. На больших объемах данных это существенно снижает скорость выполнения.Склад.ТипСклада <> ЗНАЧЕНИЕ(...) непосредственно в фильтр виртуальной таблицы усложняет работу оптимизатора SQL. СУБД не может эффективно задействовать штатные индексы регистра накопления, что приводит к сканированию всей таблицы.Период <= ДНИ.Период порождает огромный объем промежуточных данных в памяти или во временных таблицах tempdb.Рассмотрим поэтапный подход к переработке запроса. Чтобы оптимизатор СУБД построил эффективный план выполнения, разделим выборку данных и наложение фильтров на независимые шаги с использованием временных таблиц.
Разберем по шагам предложенный алгоритм:
втФильтрПоСкладам.ОстаткиИОбороты, передавая условие отбора по складам через сформированную временную таблицу.втФильтрПоНоменклатуре.Посмотрим на пример оптимизированного запроса:
ВЫБРАТЬ
спрСклад.Ссылка КАК Склад
ПОМЕСТИТЬ втФильтрПоСкладам
ИЗ
Справочник.Склады КАК спрСклад
ГДЕ
спрСклад.ТипСклада <> ЗНАЧЕНИЕ(Перечисление.ТипыСкладов.Виртуальный)
{ГДЕ
спрСклад.Ссылка КАК Склад}
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Движения.Склад КАК Склад,
Движения.Номенклатура КАК Номенклатура,
Движения.Период КАК Период,
Движения.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток,
Движения.КоличествоОборот КАК КоличествоОборот
ПОМЕСТИТЬ втДанные
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(
&НачалоПериода,
&КонецПериода,
ДЕНЬ,
,
Склад В (ВЫБРАТЬ вт.Склад ИЗ втФильтрПоСкладам КАК вт)
) КАК Движения
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
втНоменклатура.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ втФильтрПоНоменклатуре
ИЗ
(ВЫБРАТЬ РАЗЛИЧНЫЕ
втДанные.Номенклатура КАК Номенклатура
ИЗ
втДанные КАК втДанные) КАК втНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК спрНоменклатура
ПО втНоменклатура.Номенклатура = спрНоменклатура.Ссылка
{ГДЕ
спрНоменклатура.НоменклатурнаяГруппа.*,
спрНоменклатура.НоменклатурнаяГруппа.Поставщик КАК Поставщик,
спрНоменклатура.ОсновнойПоставщик.*,
спрНоменклатура.Закрыт,
спрНоменклатура.Распровождение}
ИНДЕКСИРОВАТЬ ПО
Номенклатура
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
втДанные.Склад КАК Склад,
втДанные.Номенклатура КАК Номенклатура,
втДанные.Период КАК Период,
втДанные.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток
ИЗ
втДанные КАК втДанные
ВНУТРЕННЕЕ СОЕДИНЕНИЕ втФильтрПоНоменклатуре КАК втФильтрПоНоменклатуре
ПО втДанные.Номенклатура = втФильтрПоНоменклатуре.Номенклатура
Если отчет разрабатывается с использованием Системы компоновки данных (СКД), соединять таблицу дат с виртуальной таблицей регистра вручную в тексте запроса не требуется:
ОстаткиИОбороты с периодичностью ДЕНЬ (будут получены только даты с реальными движениями).При программном выгрузке результата в коде 1С можно использовать секцию ИТОГИ с периодичностью по дням:
ИТОГИ СУММА(КоличествоКонечныйОстаток) ПО
Период ПЕРИОДАМИ(ДЕНЬ, &НачалоПериода, &КонецПериода)
Для обхода выборки в коде применяется метод РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ"). Параметр "ВСЕ" заставит платформу добавить все отсутствующие даты в периоде, автоматически сохранив актуальные остатки на каждый день.