Как ускорить медленный поиск в динамическом списке с произвольным запросом

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на управляемых формах 1С разработчики часто сталкиваются с ситуацией, когда стандартная строка поиска в динамическом списке начинает заметно зависать. Особенно ярко эта проблема проявляется при использовании произвольного запроса, даже если результирующая выборка содержит сравнительно небольшое количество строк (например, несколько тысяч записей).

Разберем причины такого поведения платформы, выясним, почему стандартный поиск работает неэффективно, и рассмотрим проверенные практические способы многократного ускорения фильтрации данных.

Почему стандартная строка поиска работает медленно

Проанализируем механизм работы стандартного поиска платформы 1С. Когда пользователь вводит текст в общую строку поиска динамического списка с произвольным запросом, происходят следующие процессы:

  1. Оборачивание во вложенный запрос: Исходный текст запроса динамического списка помещается во вложенную подвыборку. СУБД вынуждена сначала выполнить расчет всего тела запроса, включая левые соединения, объединения и группировки, а затем накладывать фильтр на полученный промежуточный результат.
  2. Сканирование по всем колонкам: Платформа генерирует условия вида ПОДОБНО "%ТекстПоиска%" для каждого видимого строкового поля. Использование знака процента в начале шаблона делает невозможным использование индексов СУБД (B-Tree индексов), что приводит к полному сканированию таблиц (Table Scan / Index Scan).
  3. Отсутствие основной таблицы: Если в свойствах динамического списка не задана ОсновнаяТаблица, отключается механизм динамического постраничного считывания, и платформа пытается обработать весь массив данных целиком.

Решение 1: Поиск через отдельный запрос и отбор по массиву ссылок

Рассмотрим наиболее эффективный способ обхода ограничений стандартного поиска, предложенный на практике. Вместо использования платформенной строки поиска мы организуем поиск через собственное поле ввода и наложение отбора на динамический список по массиву найденных ссылок.

Разберем по шагам реализацию этого механизма:

  1. Добавим на форму строковый реквизит СтрокаПоиска и выведем его в виде поля ввода.
  2. При изменении этого поля выполним на сервере быстрый и целевой запрос только по нужным полям (например, по наименованию, коду или артикулу) с отбором.
  3. Полученный массив ссылок передадим в отбор динамического списка через вид сравнения ВСписке.

Посмотрим на пример программной реализации установки такого отбора:


&НаКлиенте
Процедура СтрокаПоискаПриИзменении(Элемент)
    ВыполнитьПоискПоСтрокеНаСервере(СтрокаПоиска);
КонецПроцедуры

&НаСервере
Процедура ВыполнитьПоискПоСтрокеНаСервере(Знач ТекстПоиска)
    // Очищаем предыдущий отбор, если строка поиска пустая
    Если ПустаяСтрока(ТекстПоиска) Тогда
        ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
            Список, "Ссылка", , , Истина, Ложь
        );
        Возврат;
    КонецЕсли;
    
    // Выполняем точечный и быстрый запрос к таблице
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    Спр.Ссылка КАК Ссылка
        |ИЗ
        |    Справочник.Номенклатура КАК Спр
        |ГДЕ
        |    Спр.Наименование ПОДОБНО &ШаблонПоиска";
    
    Запрос.УстановитьПараметр("ШаблонПоиска", "%" + ТекстПоиска + "%");
    
    РезультатЗапроса = Запрос.Выполнить();
    МассивСсылок = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");
    
    // Накладываем отбор на динамический список через компоновку данных
    ПолеОтбора = Новый ПолеКомпоновкиДанных("Ссылка");
    
    // Находим или создаем элемент отбора
    ЭлементОтбора = Неопределено;
    Для Каждого Элемент Из Список.Отбор.Элементы Цикл
        Если Элемент.ЛевоеЗначение = ПолеОтбора Тогда
            ЭлементОтбора = Элемент;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Если ЭлементОтбора = Неопределено Тогда
        ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        ЭлементОтбора.ЛевоеЗначение = ПолеОтбора;
    КонецЕсли;
    
    ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
    ЭлементОтбора.ПравоеЗначение = МассивСсылок;
    ЭлементОтбора.Использование = Истина;
КонецПроцедуры

Такой подход обеспечивает высокую скорость работы, так как СУБД сначала быстро отбирает первичные ключи по целевой таблице, а динамический список затем мгновенно фильтрует строки по первичному ключу Ссылка с использованием кластерного индекса.

Решение 2: Отключение глобального поиска и поиск по конкретной колонке

Если нет необходимости разрабатывать собственную панель поиска, рассмотрим оптимизацию стандартных свойств таблицы формы и динамического списка.

  1. В свойствах таблицы динамического списка на форме установим свойство Положение строки поиска в значение Нет. Это отключит глобальный полнотекстовый перебор по всем колонкам одновременно.
  2. Пользователь сможет активировать поиск по конкретной колонке (по нажатию сочетания клавиш Ctrl + F или через контекстное меню), выбрав то поле, по которому действительно нужен отбор. Поиск по одной колонке выполняется значительно быстрее глобального.
  3. Если конфигурация поддерживает полнотекстовый поиск, убедимся, что индекс полнотекстового поиска включен и актуализирован регламентным заданием.

Решение 3: Оптимизация структуры запроса динамического списка

Проанализируем параметры самого динамического списка в конфигураторе, чтобы вернуть ему возможность эффективной динамической подгрузки данных:

  1. Установка свойства «Основная таблица»: Обязательно укажем основную таблицу в свойствах динамического списка. Это позволит платформе накладывать отборы и сортировки напрямую на таблицу базы данных, минуя избыточную материализацию вложенных запросов.
  2. Исключение лишних конструкций: Удалим из текста произвольного запроса конструкции УПОРЯДОЧИТЬ ПО, РАЗЛИЧНЫЕ и ИТОГИ. Сортировку списка необходимо настраивать стандартными средствами списка (в свойствах или через Список.Порядок), а не жестко прописывать в тексте запроса.
  3. Ограничение вычисляемых полей: Избегаем соединений с тяжелыми виртуальными таблицами и сложных выражений ВЫБОР КОГДА ... для колонок, по которым предполагается регулярный поиск.

Альтернативный вариант: Загрузка данных в таблицу формы

Если результирующий набор данных всегда ограничен небольшим объемом (в пределах 3 000 – 5 000 строк), динамический список может быть архитектурно избыточен. В этом случае выгодно полностью отказаться от динамического списка в пользу реквизита формы с типом ТаблицаЗначений (или ДанныеФормыКоллекция):

  1. При открытии формы однократно считываем все данные запросом и загружаем их в таблицу формы.
  2. Поиск, сортировка и отбор по локальной таблице выполняются на клиенте практически мгновенно, без задержек на обращение к серверу и СУБД.
← На главную