Почему зависает динамический список в журнале документов и как это исправить?

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

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

Проблема 1: Обращение к реквизитам через точку в динамическом списке

Проанализируем исходный запрос автора темы. В секции ГДЕ мы видим следующее условие:


ГДЕ
    ЕСТЬNULL(ЖурналДокументовСкладскиеДокументы.Ссылка.ВидОтгрузки, ЗНАЧЕНИЕ(Перечисление.ВидыОтгрузкиТоваров.Склад)) = ЗНАЧЕНИЕ(Перечисление.ВидыОтгрузкиТоваров.Склад)

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

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

Решение: Как правильно советуют в обсуждении, необходимо добавить реквизит ВидОтгрузки непосредственно в состав колонок самого Журнала документов на вкладке «Данные». После этого к нему можно будет обращаться напрямую: ЖурналДокументовСкладскиеДокументы.ВидОтгрузки, исключив обращение через Ссылка.

Проблема 2: Использование функций в условиях ГДЕ (Sargability)

Вторая критическая ошибка в запросе — использование функции ЕСТЬNULL в секции фильтрации. В мире баз данных существует понятие Sargable (Search Argumentable) запросов. Это запросы, которые могут эффективно использовать индексы.

Когда вы оборачиваете поле в функцию (например, ЕСТЬNULL, НАЧАЛОПЕРИОДА, ПОДСТРОКА) внутри условия ГДЕ, SQL-сервер не может использовать индекс по этому полю. Ему приходится выполнять Index Scan или Table Scan — то есть перебирать абсолютно все записи в таблице, чтобы вычислить результат функции для каждой строки, и только потом сравнивать его со значением. Если в журнале сотни тысяч записей, это гарантированное зависание.

Рекомендация по оптимизации: Избегайте функций над полями таблиц в условиях. Если вам нужно обрабатывать NULL, лучше заранее обеспечить заполнение реквизитов значениями по умолчанию или перестроить логику отбора так, чтобы она работала с «чистыми» индексированными полями.

Проблема 3: Влияние RLS (Ограничение прав на уровне записей)

Рассмотрим ситуацию: почему у администратора всё работает быстро, а у пользователя — нет? Ответ кроется в механизме RLS. Когда пользователь с ограниченными правами открывает список, платформа модифицирует ваш запрос «на лету», добавляя в него условия из ролей.

Если в ролях прописаны сложные ограничения (например, проверка прав по подразделению или складу через несколько соединений), то итоговый SQL-запрос превращается в огромного «монстра». В сочетании с вашим исходным неоптимальным запросом (с точками и ЕСТЬNULL), оптимизатор SQL-сервера может выбрать крайне неэффективный план выполнения.

Для диагностики этого состояния полезно временно дать пользователю полные права. Если проблема исчезла — значит, нужно пересматривать шаблоны RLS в конфигурации, упрощая их и избавляясь от обращений через точку внутри шаблонов ролей.

Проблема 4: Коварство пользовательских настроек

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

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

Вместо удаления пользователя, мы можем выполнить очистку настроек формы:

  1. Перейти в раздел «Администрирование».
  2. Выбрать «Настройки пользователей и прав».
  3. Найти пункт «Очистка настроек».
  4. Выбрать нужного пользователя и конкретную форму журнала.

После этого форма откроется с сортировкой по умолчанию (обычно по дате), которая работает быстро благодаря стандартным индексам.

Итоговый алгоритм действий для исправления зависаний

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

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

Выполнив эти шаги, мы превращаем «тяжелый» запрос с множеством соединений в легкую и быструю выборку из одной таблицы с использованием индексов. Это гарантирует стабильную работу журнала даже при миллионах записей в базе данных.

← На главную