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