Как оптимизировать работу динамического списка в 1С 8.3 при использовании произвольного запроса?

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

Одной из наиболее распространенных проблем производительности в интерфейсе "Такси" на платформе 1С 8.3 является медленное открытие или "торможение" при прокрутке динамических списков. Особенно остро этот вопрос встает, когда программист использует произвольный запрос с множеством соединений. В рамках данной статьи мы детально разберем, как заставить динамический список работать быстро, проанализируем внутренние механизмы платформы и внедрим лучшие практики оптимизации.

Выясним причину: почему динамический список работает медленно?

Для начала проанализируем ситуацию, как именно платформа 1С взаимодействует с СУБД при работе динамического списка. В отличие от обычного запроса, динамический список считывает данные порциями (обычно по 20–45 строк), используя конструкцию ВЫБРАТЬ ПЕРВЫЕ.... Однако, если запрос составлен неоптимально, СУБД приходится сканировать огромные объемы данных, прежде чем вернуть эти несколько строк.

Рассмотрим основные факторы, замедляющие работу:

  1. Отсутствие основной таблицы: Платформа не может эффективно применять отборы и сортировки на уровне SQL, если не понимает, по какому объекту строится список.
  2. Сложные соединения (JOIN): Соединения с виртуальными таблицами (например, ОстаткиИОбороты) или подзапросами блокируют использование индексов.
  3. Использование функций в условии ГДЕ: Любая функция (например, ПОДСТРОКА или ГОД) заставляет SQL-сервер выполнять полное сканирование таблицы (Index Scan или Table Scan).
  4. Неправильные отборы: Поиск по неиндексированным полям в списке с миллионами записей.

Шаг 1: Настройка свойства "Основная таблица"

Разберем по шагам самый важный этап. Если в настройках динамического списка поле ОсновнаяТаблица пустое, платформа лишается возможности автоматически оптимизировать запросы. Когда мы указываем основную таблицу (например, Справочник.Номенклатура или Документ.РеализацияТоваровУслуг), система начинает использовать индексы этой таблицы для всех стандартных операций: поиска, сортировки и отбора.

Проанализируем пример. Допустим, у нас есть запрос, который соединяет справочник номенклатуры с регистром сведений для получения актуальных цен. Если мы не укажем основную таблицу, поиск по наименованию будет выполняться крайне медленно. Как только мы устанавливаем ОсновнаяТаблица = Справочник.Номенклатура, платформа "понимает", что отборы по коду, наименованию или ссылке нужно транслировать напрямую в SQL-запрос к индексам этой таблицы.

Шаг 2: Оптимизация текста произвольного запроса

Рассмотрим подробнее структуру самого запроса. Часто разработчики допускают ошибку, соединяя основную таблицу с тяжелыми виртуальными таблицами без параметров. Посмотрим на пример неоптимального кода:


ВЫБРАТЬ
    СпрНоменклатура.Ссылка КАК Ссылка,
    СпрНоменклатура.Код КАК Код,
    СпрНоменклатура.Наименование КАК Наименование,
    ТоварыНаСкладахОстатки.В НаличииОстаток КАК Остаток
ИЗ
    Справочник.Номенклатура КАК СпрНоменклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
    ПО ТоварыНаСкладахОстатки.Номенклатура = СпрНоменклатура.Ссылка

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

Важный момент: если вам необходимо выводить данные из нескольких таблиц, старайтесь использовать только ЛЕВОЕ СОЕДИНЕНИЕ и следите, чтобы поля, по которым идет соединение, были проиндексированы.

Шаг 3: Программное управление отборами

Разберем, как правильно устанавливать отборы программно, чтобы не "сбивать" план запроса SQL. Вместо того чтобы динамически менять текст запроса (свойство ТекстЗапроса), что приводит к перекомпиляции плана на стороне сервера, мы должны использовать коллекцию Отбор или параметры запроса.

Посмотрим на пример правильной установки параметра в динамическом списке:


// Установка параметра для виртуальной таблицы внутри списка
Список.Параметры.УстановитьЗначениеПараметра("Период", ТекущаяДата());

// Программная установка отбора
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.Использование = Истина;
ЭлементОтбора.ПравоеЗначение = ВыбранныйСклад;

Использование ПолеКомпоновкиДанных позволяет платформе встроить условие непосредственно в SQL-запрос наиболее эффективным способом.

Шаг 4: Использование динамического считывания данных

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

Практические советы по работе с полями

Проанализируем еще несколько тонкостей, которые помогут ускорить ваш интерфейс:

  1. Минимизируйте количество колонок: Каждая колонка в списке — это дополнительные данные, передаваемые по сети. Убирайте невидимые по умолчанию или редко используемые поля из запроса.
  2. Избегайте обращений через точку: Например, Ссылка.Склад.Организация.Наименование в запросе динамического списка порождает дополнительные неявные соединения (JOIN), что сильно нагружает сервер. Лучше вынести нужные поля в сам запрос через явное соединение.
  3. Осторожно с условным оформлением: Сложные правила раскраски строк (например, проверка остатка для каждой строки через функцию) выполняются на стороне клиента и могут тормозить отрисовку формы.

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

← На главную