Разберем распространенную ситуацию, когда запрос к табличной части документа всего на несколько десятков строк выполняется 5–7 секунд. С такой проблемой часто сталкиваются разработчики при формировании печатных форм и отчетов в типовых и нетиповых конфигурациях. Выясним причину такого падения производительности и рассмотрим способы оптимизации запроса.
Посмотрим на типичный фрагмент запроса, вызывающий существенную задержку:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ИнвентаризацияОСОС.НомерСтроки КАК НомерСтроки,
ИнвентаризацияОСОС.ОсновноеСредство КАК ОсновноеСредство,
ВЫБОР
КОГДА ИнвентаризацияОСОС.ОсновноеСредство.НаименованиеПолное ПОДОБНО """"
ТОГДА ИнвентаризацияОСОС.ОсновноеСредство.Наименование
ИНАЧЕ ИнвентаризацияОСОС.ОсновноеСредство.НаименованиеПолное
КОНЕЦ КАК ОсновноеСредствоНаименованиеПолное,
ИнвентаризацияОСОС.ОсновноеСредство.ДатаВыпуска КАК ДатаВыпуска,
ИнвентаризацияОСОС.ОсновноеСредство.ЗаводскойНомер КАК ЗаводскойНомер,
ИнвентаризацияОСОС.вчИнвентарныйНомер КАК ИнвентарныйНомер,
ИнвентаризацияОСОС.вчРегистратор КАК Регистратор,
ИнвентаризацияОСОС.вчРегистратор.Дата КАК РегистраторДата,
ИнвентаризацияОСОС.вчРегистратор.Номер КАК РегистраторНомер,
ИнвентаризацияОСОС.вчВСоставе,
ИнвентаризацияОСОС.ОсновноеСредство.НомерПаспорта КАК НомерПаспорта,
ИнвентаризацияОСОС.СтоимостьПоДаннымУчета КАК СтоимостьПоДаннымУчета,
ИнвентаризацияОСОС.СтоимостьФактическая КАК СтоимостьФактическая
ИЗ
Документ.ИнвентаризацияОС.ОС КАК ИнвентаризацияОСОС
ГДЕ
ИнвентаризацияОСОС.Ссылка = &Ссылка
УПОРЯДОЧИТЬ ПО
НомерСтроки
Проанализируем основные факторы, приводящие к медленному выполнению:
ДокументСсылка, ЛюбаяСсылка). Если реквизит вчРегистратор имеет составной тип или обобщенный тип ДокументСсылка, обращение через точку к его полям (вчРегистратор.Дата, вчРегистратор.Номер) заставляет платформу формировать на уровне СУБД неявные левые соединения (LEFT JOIN) со всеми существующими таблицами документов конфигурации. В крупных конфигурациях (например, УПП, ERP или КА) это сотни таблиц. В результате СУБД тратит львиную долю времени не на выборку строк, а на компиляцию гигантского плана выполнения SQL-запроса.РАЗРЕШЕННЫЕ указывает платформе добавить условия проверки прав на уровне записей. При наличии сотен неявных соединений со всеми таблицами документов условия RLS добавляются к каждой присоединенной таблице, превращая SQL-текст в огромную конструкцию со множеством вложенных подзапросов.ОсновноеСредство.НаименованиеПолное, ОсновноеСредство.ДатаВыпуска, ОсновноеСредство.ЗаводскойНомер генерируют дополнительные неявные соединения.ПОДОБНО для проверки пустой строки. Реквизит НаименованиеПолное часто имеет неограниченную длину. Применение конструкции ПОДОБНО """" транслируется в ресурсоемкую проверку LIKE в SQL.Если тип реквизита вчРегистратор в метаданных нельзя сузить, но в документе реально используются только несколько конкретных видов документов, необходимо явно указать типы с помощью конструкции ВЫРАЗИТЬ. Это избавит платформу от необходимости соединять таблицы всех документов конфигурации.
Посмотрим на пример правильного получения даты и номера регистратора:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ИнвентаризацияОСОС.НомерСтроки КАК НомерСтроки,
ИнвентаризацияОСОС.ОсновноеСредство КАК ОсновноеСредство,
ВЫБОР
КОГДА ИнвентаризацияОСОС.вчРегистратор ССЫЛКА Документ.ПринятиеКУчетуОС
ТОГДА ВЫРАЗИТЬ(ИнвентаризацияОСОС.вчРегистратор КАК Документ.ПринятиеКУчетуОС).Номер
КОГДА ИнвентаризацияОСОС.вчРегистратор ССЫЛКА Документ.ВводНачальныхОстатковОС
ТОГДА ВЫРАЗИТЬ(ИнвентаризацияОСОС.вчРегистратор КАК Документ.ВводНачальныхОстатковОС).Номер
ИНАЧЕ """""
КОНЕЦ КАК РегистраторНомер,
ВЫБОР
КОГДА ИнвентаризацияОСОС.вчРегистратор ССЫЛКА Документ.ПринятиеКУчетуОС
ТОГДА ВЫРАЗИТЬ(ИнвентаризацияОСОС.вчРегистратор КАК Документ.ПринятиеКУчетуОС).Дата
КОГДА ИнвентаризацияОСОС.вчРегистратор ССЫЛКА Документ.ВводНачальныхОстатковОС
ТОГДА ВЫРАЗИТЬ(ИнвентаризацияОСОС.вчРегистратор КАК Документ.ВводНачальныхОстатковОС).Дата
ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1)
КОНЕЦ КАК РегистраторДата
ИЗ
Документ.ИнвентаризацияОС.ОС КАК ИнвентаризацияОСОС
ГДЕ
ИнвентаризацияОСОС.Ссылка = &Ссылка
Разберем архитектурные изменения, которые навсегда исключат подобные проблемы:
вчРегистратор может содержать только определенные документы, откроем свойства реквизита в дереве метаданных и вместо общего флага ДокументСсылка выберем конкретные типы документов флажками.НаличиеПоДаннымУчета имеют тип Булево, Число, для каждой строки на уровне базы создаются дополнительные поля проверки типов. Рекомендуется задать строгий тип Число или Булево.Для исключения многократных неявных соединений к справочнику ОсновныеСредства и оптимизации проверки строк перепишем запрос с использованием временных таблиц и явного ЛЕВОЕ СОЕДИНЕНИЕ:
ВЫБРАТЬ
ИнвентаризацияОСОС.НомерСтроки КАК НомерСтроки,
ИнвентаризацияОСОС.ОсновноеСредство КАК ОсновноеСредство,
ИнвентаризацияОСОС.вчРегистратор КАК Регистратор,
ИнвентаризацияОСОС.вчИнвентарныйНомер КАК ИнвентарныйНомер,
ИнвентаризацияОСОС.вчВСоставе КАК вчВСоставе,
ИнвентаризацияОСОС.СтоимостьПоДаннымУчета КАК СтоимостьПоДаннымУчета,
ИнвентаризацияОСОС.СтоимостьФактическая КАК СтоимостьФактическая
ПОМЕСТИТЬ ВТ_СтрокиДокумента
ИЗ
Документ.ИнвентаризацияОС.ОС КАК ИнвентаризацияОСОС
ГДЕ
ИнвентаризацияОСОС.Ссылка = &Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Строки.НомерСтроки КАК НомерСтроки,
Строки.ОсновноеСредство КАК ОсновноеСредство,
ВЫБОР
КОГДА СпрОС.НаименованиеПолное = """"
ТОГДА СпрОС.Наименование
ИНАЧЕ СпрОС.НаименованиеПолное
КОНЕЦ КАК ОсновноеСредствоНаименованиеПолное,
СпрОС.ДатаВыпуска КАК ДатаВыпуска,
СпрОС.ЗаводскойНомер КАК ЗаводскойНомер,
СпрОС.НомерПаспорта КАК НомерПаспорта,
Строки.ИнвентарныйНомер КАК ИнвентарныйНомер,
Строки.Регистратор КАК Регистратор,
Строки.вчВСоставе КАК вчВСоставе,
Строки.СтоимостьПоДаннымУчета КАК СтоимостьПоДаннымУчета,
Строки.СтоимостьФактическая КАК СтоимостьФактическая
ИЗ
ВТ_СтрокиДокумента КАК Строки
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ОсновныеСредства КАК СпрОС
ПО Строки.ОсновноеСредство = СпрОС.Ссылка
УПОРЯДОЧИТЬ ПО
Строки.НомерСтроки
Если печатная форма строится для уже открытого пользователем документа, наложение условий RLS на таблицы запроса часто является избыточным. Для отключения проверки прав и ускорения компиляции запроса применим вызов привилегированного режима в коде модуля печати:
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст = "...";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
РезультатЗапроса = Запрос.Выполнить();
УстановитьПривилегированныйРежим(Ложь);
Важно: При выполнении в привилегированном режиме ключевое слово РАЗРЕШЕННЫЕ в тексте запроса следует убрать, так как контроль прав доступа на уровне записей временно отключается.