Почему зависает загрузка из регистра накопления в 1С и как оптимизировать запрос

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

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

Анализ исходного запроса: ищем «узкие места»

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


ВЫБРАТЬ
    ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
    ТоварыНаСкладахОстатки.Номенклатура.Родитель КАК Родитель,
    ВЫБОР
        КОГДА ТоварыНаСкладахОстатки.Номенклатура.Родитель.Родитель = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
            ТОГДА ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
        ИНАЧЕ ТоварыНаСкладахОстатки.Номенклатура.Родитель.Родитель
    КОНЕЦ КАК Родитель2,
    ТоварыНаСкладахОстатки.Номенклатура.Родитель.Код КАК КодРодителя,
    ТоварыНаСкладахОстатки.Номенклатура.Артикул КАК Артикул,
    ЛОЖЬ КАК УстановитьФлажок
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&Кон, Номенклатура.Родитель В ИЕРАРХИИ (&Родитель)) КАК ТоварыНаСкладахОстатки
ГДЕ
    ТоварыНаСкладахОстатки.Номенклатура.ПометкаУдаления = ЛОЖЬ
    И ТоварыНаСкладахОстатки.Номенклатура.Наименование ПОДОБНО "%" + &Наим1 + "%"
    И ТоварыНаСкладахОстатки.Номенклатура.Наименование ПОДОБНО "%" + &Наим2 + "%"

Проанализируем ситуацию. Основные проблемы здесь связаны с тем, как СУБД (SQL Server или PostgreSQL) интерпретирует этот запрос и как платформа 1С преобразует его в SQL-код.

Проблема №1: Разыменование ссылок («через точку»)

В запросе активно используется обращение к полям через точку: Номенклатура.Родитель.Родитель, Номенклатура.Артикул и т.д. В мире 1С это называется «разыменованием ссылки». На уровне базы данных каждое такое обращение превращается в LEFT JOIN с таблицей справочника.

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

Решение: Старайтесь избегать глубоких цепочек точек в секции ВЫБРАТЬ. Если данных много, лучше сначала получить список ссылок во временную таблицу, а затем одним соединением вытянуть все необходимые реквизиты.

Проблема №2: Условие ПОДОБНО с процентом в начале

Конструкция Наименование ПОДОБНО "%" + &Наим + "%" является одной из самых тяжелых для базы данных. Когда символ процента стоит в начале строки поиска, СУБД не может использовать индексы. Вместо быстрого поиска по индексу сервер вынужден выполнять полное сканирование (Full Scan) всей таблицы справочника номенклатуры для каждой строки остатков.

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

Проблема №3: Неоптимальный иерархический отбор

Разберем условие в параметрах виртуальной таблицы: Номенклатура.Родитель В ИЕРАРХИИ (&Родитель). Здесь опять используется точка. Платформе гораздо проще обработать прямое условие по ссылке.

Рекомендация: Замените условие на Номенклатура В ИЕРАРХИИ (&Родитель). Сама платформа 1С при выполнении В ИЕРАРХИИ эффективно обрабатывает вложенность, и лишнее обращение к родителю только усложняет задачу оптимизатору SQL.

Проблема №4: Использование ГДЕ вместо параметров виртуальной таблицы

В тексте темы автор упоминает, что переносил условия из параметров виртуальной таблицы в секцию ГДЕ. Это критическая ошибка для производительности. Рассмотрим разницу:

  1. Параметры виртуальной таблицы: 1С передает фильтр в SQL-запрос таким образом, что СУБД отбирает только нужные записи еще на этапе расчета остатков.
  2. Секция ГДЕ: СУБД сначала рассчитывает остатки по всем товарам (или по тем, что прошли через параметры ВТ), а затем «выкидывает» лишние строки.

Если в параметрах ВТ стоит только иерархия, а остальные фильтры в ГДЕ, система может сначала обрабатывать десятки тысяч записей, хотя на выходе нам нужно всего 700. Всегда старайтесь максимально ограничивать выборку именно в параметрах виртуальной таблицы.

Как правильно переписать запрос

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


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

// 2. Теперь получаем остатки только по отобранному списку
ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    Остатки.Номенклатура.Родитель КАК Родитель,
    Остатки.Номенклатура.Артикул КАК Артикул
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&Кон, Номенклатура В (ВЫБРАТЬ Ссылка ИЗ ВТ_ОтфильтрованнаяНоменклатура)) КАК Остатки

Внешние причины зависания: Актуальность итогов

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

Если итоги в базе рассчитаны на 31 декабря прошлого года, а вы просите остатки на «сегодня», 1С вынуждена выполнить следующее:

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

Если в течение часа в базу активно вводились новые документы, объем данных для «досчета» увеличивается. В какой-то момент этот объем становится критическим, и запрос «зависает». Выясним, так ли это, проверив дату актуальности итогов в консоли управления или через «Операции — Управление итогами».

Коварная команда «Вопрос» и модальность

В ходе обсуждения автор заметил, что зависание иногда происходит на команде Вопрос(). Это очень важный симптом. В управляемых формах 1С 8.3 использование модальных окон (к которым относится классический «Вопрос») не рекомендуется и часто приводит к блокировкам интерфейса.

Что происходит на самом деле: Окно вопроса может появиться на заднем плане (за основным окном программы), особенно при работе через удаленный рабочий стол (RDP). Пользователь не видит окна, не может нажать кнопку, а весь интерфейс 1С заблокирован, ожидая ответа. Это выглядит как полное зависание приложения.

Решение: Используйте асинхронные методы (ПоказатьВопрос) вместо модальных. Это позволит избежать блокировки потока выполнения.

Итоги и рекомендации

Для того чтобы ваша обработка работала стабильно и быстро, выполните следующие шаги:

Соблюдение этих правил позволит вашей обработке работать стабильно даже при больших объемах данных и длительных сеансах работы в системе 1С:Розница.

← На главную