При разработке интерфейсов на управляемых формах 1С часто возникает задача отображения больших списков документов или справочников с миллионами записей. Если в динамическом списке используется произвольный запрос с пакетом временных таблиц, соединениями или разыменованием ссылочных полей через точку, установка пользовательского или программного отбора может приводить к критическим задержкам (вплоть до десятков секунд). Разберем причины такого поведения платформы и подробно рассмотрим эффективные способы оптимизации.
Для понимания проблемы проанализируем, как платформа 1С и система компоновки данных (СКД) обрабатывают динамические списки:
Список.Отбор, платформа не всегда способна автоматически протолкнуть условие внутрь временных таблиц сложного пакета. В результате весь пакет временных таблиц рассчитывается целиком по всему объему таблицы (например, по 1,5 миллионам документов), и только к итоговому результату применяется внешнее условие фильтрации.ТипЗаявки.Родитель = &Значение на уровне СУБД приводит к неявному левому соединению (LEFT JOIN). Если реквизит ТипЗаявки в документе не проиндексирован, СУБД сканирует всю таблицу целиком (Table Scan / Clustered Index Scan).Чтобы условия отбора динамического списка применялись непосредственно на этапе сбора данных во временные таблицы, а не к финальному результату пакета, используем конструкции расширения языка запросов СКД с фигурными скобками {ГДЕ ...}.
Рассмотрим пример правильной структуры запроса динамического списка:
ВЫБРАТЬ
Заявка.Ссылка КАК Ссылка,
Заявка.Номер КАК Номер,
Заявка.Дата КАК Дата,
Заявка.ТипЗаявки КАК ТипЗаявки
ПОМЕСТИТЬ ВТ_ОтфильтрованныеЗаявки
ИЗ
Документ.Заявка КАК Заявка
{ГДЕ
Заявка.ТипЗаявки.* КАК ТипЗаявки,
Заявка.ТипЗаявки.Родитель.* КАК ТипЗаявкиРодитель}
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ.Ссылка КАК Ссылка,
ВТ.Номер КАК Номер,
ВТ.Дата КАК Дата,
ВТ.ТипЗаявки КАК ТипЗаявки
ИЗ
ВТ_ОтфильтрованныеЗаявки КАК ВТ
Благодаря блоку {ГДЕ ...} система компоновки данных встроит условие отбора списка внутрь первого запроса пакета, что сократит объем промежуточных данных во временной таблице.
Проанализируем обращение к реквизитам через точку в условиях отбора. Конструкция ТипЗаявки.Родитель требует выполнения соединения таблиц. Для ускорения заменим проверку родителя на прямое сравнение со списком всех его дочерних элементов.
Посмотрим на пример программной установки отбора:
// 1. Получаем массив всех элементов нужной группы
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТипыЗаявок.Ссылка КАК Ссылка
|ИЗ
| Справочник.ТипыЗаявок КАК ТипыЗаявок
|ГДЕ
| ТипыЗаявок.Родитель = &РодительИерархии";
Запрос.УстановитьПараметр("РодительИерархии", ПредопределенноеЗначение("Справочник.ТипыЗаявок.СервисныеЗаявки"));
СписокТипов = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
// 2. Устанавливаем отбор по прямому полю через список
ОтборСписка = Список.Отбор.Элементы;
ОтборСписка.Очистить();
ЭлементОтбора = ОтборСписка.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ТипЗаявки");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = СписокТипов;
ЭлементОтбора.Использование = Истина;
Такой подход позволяет СУБД использовать прямой индекс по реквизиту ТипЗаявки без выполнения дополнительных соединений.
Если условие фильтрации является фиксированным элементом интерфейса, вынесем его в явный параметр запроса вместо использования динамического отбора СКД.
В тексте запроса динамического списка задаем условие:
ВЫБРАТЬ
Заявка.Ссылка КАК Ссылка,
Заявка.Номер КАК Номер,
Заявка.Дата КАК Дата,
Заявка.ТипЗаявки КАК ТипЗаявки
ИЗ
Документ.Заявка КАК Заявка
ГДЕ
(&НеИспользоватьФильтрПоТипу ИЛИ Заявка.ТипЗаявки.Родитель = &РодительТипа)
На форме управляем значением параметра программно:
Список.Параметры.УстановитьЗначениеПараметра("РодительТипа", ПредопределенноеЗначение("Справочник.ТипыЗаявок.СервисныеЗаявки"));
Список.Параметры.УстановитьЗначениеПараметра("НеИспользоватьФильтрПоТипу", Ложь);
Разберем обязательные настройки динамического списка и объектов метаданных, влияющие на скорость выполнения запроса:
Документ.Заявка). Это позволяет платформе генерировать оптимизированный SQL-запрос для порционного считывания данных.ТипЗаявки), в дереве метаданных конфигуратора должно быть установлено свойство Индексировать или Индексировать с дополнительным упорядочиванием.DBMSSQL / DBPOSTGRS) или профайлер СУБД. Проанализируем план выполнения (Execution Plan) на наличие операций Table Scan и отсутствующих индексов.