При разработке механизмов подбора номенклатуры в конфигурации «Управление торговлей 10.3» часто возникает необходимость сопоставить текущие складские партии товара с исходным документом поставки. Типичная задача: товар был оприходован, затем перемещен на другой склад, и в форме подбора требуется отобразить не только партию и перемещенное количество со стоимостью, но и исходный объем поставки из табличной части документа ПоступлениеТоваровУслуг.
Попытка соединить виртуальную таблицу регистра партий напрямую с табличной частью документа или использование вложенных подзапросов в секции ИЗ нередко приводит к резкому падению производительности — запрос начинает выполняться по несколько секунд, что совершенно неприемлемо для интерактивной работы пользователя. Разберем по шагам, почему возникают задержки и как правильно переписать запрос для максимального быстродействия.
Рассмотрим исходный вариант неоптимального запроса, с которым часто сталкиваются разработчики:
ВЫБРАТЬ
ПартииТоваровНаСкладахОстаткиИОбороты.ДокументОприходования КАК ДокументОприходования,
ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоПриход,
ПартииТоваровНаСкладахОстаткиИОбороты.СтоимостьПриход,
ВложенныйЗапрос.Количество
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах.ОстаткиИОбороты(
,
,
Регистратор,
,
Номенклатура = &Номенклатура
И Склад = &Склад) КАК ПартииТоваровНаСкладахОстаткиИОбороты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
ПоступлениеТоваровУслугТовары.Ссылка КАК Ссылка,
ПоступлениеТоваровУслугТовары.Номенклатура КАК Номенклатура,
ПоступлениеТоваровУслугТовары.Количество КАК Количество
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
ГДЕ
ПоступлениеТоваровУслугТовары.Номенклатура.Ссылка = &Номенклатура) КАК ВложенныйЗапрос
ПО ПартииТоваровНаСкладахОстаткиИОбороты.ДокументОприходования.Ссылка = ВложенныйЗапрос.Ссылка
Проанализируем ситуацию и выделим грубые ошибки, приводящие к замедлению:
ПоступлениеТоваровУслугТовары.Номенклатура.Ссылка и ДокументОприходования.Ссылка заставляют СУБД выполнять неявные левые соединения со справочниками и таблицами документов. В условиях сравнения достаточно использовать саму ссылку без обращения к ее реквизиту Ссылка.Регистратор вынуждает платформу вычислять остатки на момент каждого движения регистра. Это тяжелая операция, которая многократно увеличивает время формирования выборки.ИЗ: СУБД не всегда может эффективно построить план выполнения при соединении с виртуальной таблицей подзапроса без явной индексации.ДокументОприходования в регистре партий содержит составной тип (множество различных видов документов). При соединении по такому полю без ограничения типа СУБД вынуждена сканировать таблицы всех возможных типов документов, что резко снижает скорость.Выясним причину использования таблицы ОстаткиИОбороты. Если в форме требуется отразить только движения прихода (поступление по перемещению, партии и стоимость), расчет остатков вовсе не требуется. В таком случае следует переключиться на виртуальную таблицу Обороты либо обращаться к реальной таблице движений РегистрНакопления.ПартииТоваровНаСкладах.
Если же остаток товара на складе все же нужен, используют таблицу Остатки без детализации по регистратору. В рамках нашей задачи достаточно получить обороты прихода:
ВЫБРАТЬ
ПартииТоваров.ДокументОприходования КАК ДокументОприходования,
ПартииТоваров.КоличествоОборот КАК КоличествоПриход,
ПартииТоваров.СтоимостьОборот КАК СтоимостьПриход
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах.Обороты(
&НачалоПериода,
&КонецПериода,
Период,
Номенклатура = &Номенклатура
И Склад = &Склад) КАК ПартииТоваров
Чтобы избежать блокировок и неоптимальных планов выполнения СУБД, разделим сбор данных на этапы с использованием временных таблиц. Также применим функцию ВЫРАЗИТЬ для поля составного типа и сгруппируем табличную часть документа поступления, чтобы исключить дубли строк.
Посмотрим на пример правильного комплексного пакета запросов:
ВЫБРАТЬ
ВЫРАЗИТЬ(Партии.ДокументОприходования КАК ДокументСсылка.ПоступлениеТоваровУслуг) КАК ДокументПоступления,
Партии.Номенклатура КАК Номенклатура,
СУММА(Партии.Количество) КАК КоличествоПриход,
СУММА(Партии.Стоимость) КАК СтоимостьПриход
ПОМЕСТИТЬ ВТ_ПартииТоваров
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах КАК Партии
ГДЕ
Партии.Номенклатура = &Номенклатура
И Партии.Склад = &Склад
И Партии.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
И Партии.ДокументОприходования ССЫЛКА Документ.ПоступлениеТоваровУслуг
СГРУППИРОВАТЬ ПО
ВЫРАЗИТЬ(Партии.ДокументОприходования КАК ДокументСсылка.ПоступлениеТоваровУслуг),
Партии.Номенклатура
ИНДЕКСИРОВАТЬ ПО
ДокументПоступления,
Номенклатура
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ПартииТоваров.ДокументПоступления КАК ДокументОприходования,
ВТ_ПартииТоваров.КоличествоПриход КАК КоличествоПриход,
ВТ_ПартииТоваров.СтоимостьПриход КАК СтоимостьПриход,
ЕСТЬNULL(ПоступлениеТовары.КоличествоВПоступлении, 0) КАК КоличествоВПоступлении
ИЗ
ВТ_ПартииТоваров КАК ВТ_ПартииТоваров
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
ТЧ.Ссылка КАК Ссылка,
ТЧ.Номенклатура КАК Номенклатура,
СУММА(ТЧ.Количество * ТЧ.Коэффициент) КАК КоличествоВПоступлении
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК ТЧ
ГДЕ
ТЧ.Ссылка В
(ВЫБРАТЬ
ВТ.ДокументПоступления
ИЗ
ВТ_ПартииТоваров КАК ВТ)
И ТЧ.Номенклатура = &Номенклатура
СГРУППИРОВАТЬ ПО
ТЧ.Ссылка,
ТЧ.Номенклатура) КАК ПоступлениеТовары
ПО ВТ_ПартииТоваров.ДокументПоступления = ПоступлениеТовары.Ссылка
И ВТ_ПартииТоваров.Номенклатура = ПоступлениеТовары.Номенклатура
Рассмотрим важный нюанс прикладного решения «Управление торговлей 10.3». В табличной части Товары документов количество хранится в тех единицах измерения, которые выбрал пользователь (реквизит ЕдиницаИзмерения), а реальный пересчет в базовые единицы хранения остатков осуществляется через реквизит Коэффициент.
В регистре накопления ПартииТоваровНаСкладах движения всегда формируются в базовых единицах (единицах хранения остатков). Если мы просто выберем поле Количество из табличной части поступления, в случае использования упаковок или коробок числа разойдутся. Поэтому в запросе обязательно используем формулу:
СУММА(ТЧ.Количество * ТЧ.Коэффициент) КАК КоличествоВПоступлении
Для интерактивных форм подбора критически важна скорость отклика. Если запрос выполняется при активизации каждой строки или при каждом клике, соблюдайте следующие правила:
&Номенклатура, а не выполняя запрос в цикле по каждой позиции.