Почему список документов открывается слишком долго и как это исправить?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

Медленное открытие списков документов — одна из самых распространенных жалоб пользователей в крупных информационных базах на платформе 1С:Предприятие 8. Особенно остро проблема проявляется в самописных документах или при использовании сложных Динамических списков с произвольными запросами. В этой статье мы подробно разберем причины возникновения «тормозов», проанализируем конкретные примеры неоптимального кода и выясним, как ускорить работу интерфейса в несколько раз.

Поиск «узкого места»: с чего начать диагностику?

Когда список открывается за 10–15 секунд при небольшом объеме данных, нам необходимо локализовать проблему. Давайте проанализируем стандартный алгоритм проверки, который поможет отсечь лишнее:

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

Разберем ситуацию на примере реального запроса, который привел к существенным задержкам:


ВЫБРАТЬ
    ДокументИзвещение.Ссылка,
    МАКСИМУМ(ДокументИзвещение.ВерсияДанных) КАК ВерсияДанных,
    МАКСИМУМ(ДокументИзвещение.Номер) КАК Номер,
    МАКСИМУМ(ДокументИзвещение.Дата) КАК Дата,
    МАКСИМУМ(ЕСТЬNULL(ИностранныеНаименования.ИностранноеНаименование, ДокументИзвещение.Номенклатура.Наименование)) КАК Наименование,
    МАКСИМУМ(ПеремещениеТоваров.Ссылка) КАК Перемещение
ИЗ
    Документ.Извещение КАК ДокументИзвещение
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ИностранныеНаименования КАК ИностранныеНаименования
    ПО ДокументИзвещение.Номенклатура = ИностранныеНаименования.Объект
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПеремещениеТоваров КАК ПеремещениеТоваров
    ПО ДокументИзвещение.Ссылка = ПеремещениеТоваров.ДокументОснование
СГРУППИРОВАТЬ ПО
    ДокументИзвещение.Ссылка

Проблема №1: Использование СГРУППИРОВАТЬ ПО (GROUP BY)

Давайте выясним, почему использование группировки в динамическом списке — это плохая практика. Платформа 1С оптимизирует работу списков, считывая данные порциями (например, по 30–45 записей), чтобы пользователь мгновенно увидел первые строки. Однако, когда мы добавляем СГРУППИРОВАТЬ ПО, СУБД (например, MS SQL Server) не может вернуть первые 30 строк, пока не обработает всю таблицу и не выполнит операцию агрегации. Это полностью нивелирует механизм порционного считывания.

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

Проблема №2: Разыменование полей (обращение через точку)

Посмотрим на конструкцию из примера выше: ДокументИзвещение.Номенклатура.Наименование. В языке запросов 1С это называется разыменованием. На уровне SQL это превращается в еще одно ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN). Если поле Номенклатура имеет составной тип, количество скрытых соединений растет в геометрической прогрессии.

Особую опасность представляют конструкции типа:

Документ.ПриходныйОрдерНаТовары.ДокументПеремещения.ДокументОснование

Здесь мы видим тройное разыменование. Каждая «точка» — это потенциальный удар по производительности. Если ДокументОснование — составной тип, включающий 10 видов документов, СУБД придется выполнить колоссальный объем работы только для того, чтобы отобразить список.

Проблема №3: Неиндексированные поля в соединениях

Проанализируем соединение с таблицей Документ.ПеремещениеТоваров по полю ДокументОснование. Чтобы такое соединение работало быстро, реквизит ДокументОснование в конфигураторе должен иметь установленный флаг Индексировать. Если индекса нет, СУБД будет выполнять полное сканирование таблицы перемещений для каждой строки основного документа, что и вызывает задержку в 10–15 секунд.

Как оптимизировать запрос: пошаговое руководство

Рассмотрим, как можно переписать тяжелый запрос. Во-первых, проанализируем, действительно ли нам нужны агрегатные функции (МАКСИМУМ, СУММА). Если мы хотим просто отобразить реквизиты документа, группировка не нужна.

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


ВЫБРАТЬ
    ДокументИзвещение.Ссылка КАК Ссылка,
    ДокументИзвещение.Дата КАК Дата,
    ДокументИзвещение.Номер КАК Номер,
    ДокументИзвещение.Организация КАК Организация,
    ДокументИзвещение.Номенклатура КАК Номенклатура
ИЗ
    Документ.Извещение КАК ДокументИзвещение

В настройках динамического списка обязательно укажем Основную таблицу (Документ.Извещение). Это критически важно для корректной работы индексов и стандартных команд списка.

Архитектурное решение: использование регистра сведений

Если бизнес-логика требует отображать в списке данные, которые невозможно получить простым запросом (например, сложные расчеты остатков, статусы из разных документов, иностранные наименования), лучшим решением будет создание специального Регистра сведений.

Алгоритм реализации:

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

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

Разбор «антипаттерна»: сложные условия ВЫБОР (CASE)

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


ВЫБОР 
    КОГДА НормыТО.ПериодичностьОбслуживания = ЗНАЧЕНИЕ(Перечисление.Периодичность.Год) 
        ТОГДА ДОБАВИТЬКДАТЕ(ЕСТЬNULL(уатПрохождениеТО.Период, НормыТО.Дата), ГОД, 1)
    КОГДА НормыТО.ПериодичностьОбслуживания = ЗНАЧЕНИЕ(Перечисление.Периодичность.Месяц) 
        ТОГДА ДОБАВИТЬКДАТЕ(ЕСТЬNULL(уатПрохождениеТО.Период, НормыТО.Дата), МЕСЯЦ, 1)
    ИНАЧЕ ...
КОНЕЦ КАК СрокСледующегоТО

Подобные вычисления «на лету» для каждой строки списка создают огромную нагрузку на процессор сервера БД. Если таких условий десятки, список будет подтормаживать при прокрутке. Выясним причину: СУБД вынуждена вычислять эти значения для каждой порции данных. Правильный подход — рассчитать эти значения заранее в документе и хранить их в реквизитах, либо вынести в отдельный регистр.

Дополнительные факторы: RLS и Статистика SQL

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

Также не забывайте о регламентных операциях на стороне SQL-сервера. Обновление статистики (Update Statistics) и дефрагментация индексов часто решают проблемы производительности, которые невозможно исправить одним лишь изменением кода.

Подведем итог: Для ускорения списка документов необходимо минимизировать количество соединений, полностью отказаться от СГРУППИРОВАТЬ ПО, следить за индексацией полей связи и, в сложных случаях, использовать вспомогательные регистры для хранения подготовленных данных.

← На главную