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