Как устранить зависания при проведении документов в УТ 11.5 и ERP 2.5 при использовании онлайн-взаиморасчетов

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

В современных релизах конфигураций 1С:Управление торговлей (с версии 11.5.22.137) и 1С:ERP (с версии 2.5) пользователи часто сталкиваются с существенным замедлением работы системы при проведении отгрузочных документов (например, «Реализация товаров и услуг»). Проблема проявляется наиболее остро, если в настройках системы включен режим «Онлайн-взаиморасчеты». Рассмотрим причины возникновения этой ситуации, проанализируем технические аспекты и разберем готовое решение для оптимизации производительности.

Выясним причину: почему возникают тормоза

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

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

  1. Использование функции НАЧАЛОПЕРИОДА() над полями физической таблицы в условии соединения делает запрос non-SARGable (не пригодным для поиска по индексу).
  2. SQL-сервер не может применить существующие индексы по полям Период, Регистратор или ДатаПлатежа, так как ему необходимо вычислить результат функции для каждой строки таблицы перед сравнением.
  3. Вместо быстрого поиска (Index Seek) происходит полное сканирование индекса или таблицы (Index Scan / Table Scan). На больших базах данных, где регистры взаиморасчетов содержат миллионы записей, это приводит к многоминутным ожиданиям и блокировкам.

Ситуация официально зарегистрирована как ошибка 1С за номером 00-00851745.

Разберем по шагам оптимизацию запроса

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

Рассмотрим пример исправления кода через механизм расширений с использованием аннотации &ИзменениеИКонтроль. Посмотрим на алгоритм реализации:


&ИзменениеИКонтроль("ЗаполнитьВспомогательнуюИнформацию")
Процедура ОптимизированнаяЗаполнитьВспомогательнуюИнформацию(МенеджерВТ, ЭтоРасчетыСКлиентами)
    Запрос = Новый Запрос;
    Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
    
    // Подготовим текст запроса, разделяя соединение на этапы
    ТекстЗапроса = "
    |ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    ВЫБОР КОГДА Изменения.РасчетныйДокумент ССЫЛКА Документ.ПервичныйДокумент
    |                        И Изменения.РасчетныйДокумент <> ЗНАЧЕНИЕ(Документ.ПервичныйДокумент.ПустаяСсылка)
    |        ТОГДА Изменения.РасчетныйДокумент
    |        ИНАЧЕ Изменения.Документ
    |    КОНЕЦ                                   КАК РасчетныйДокумент,
    |    НАЧАЛОПЕРИОДА(ВЫБОР КОГДА Изменения.ДатаПлатежа = ДАТАВРЕМЯ(1,1,1) ИЛИ Изменения.Сторно
    |                        ТОГДА Изменения.ДатаРегистратора
    |                        ИНАЧЕ Изменения.ДатаПлатежа
    |                    КОНЕЦ , ДЕНЬ)      КАК ДатаПлановогоПогашения
    |ПОМЕСТИТЬ ИзмененияВспомогательнойИнформации
    |ИЗ
    |    &РасчетыИзменения КАК Изменения
    |ГДЕ
    |    Изменения.Сумма <> 0 ИЛИ Изменения.КОтгрузке <> 0 ИЛИ Изменения.КОплате <> 0
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |// ЭТАП 1: Предварительный отбор данных по индексированным полям
    |ВЫБРАТЬ
    |    Расчеты.Регистратор КАК Регистратор,
    |    Расчеты.ДатаПлатежа КАК ДатаПлатежа,
    |    Расчеты.ДатаРегистратора КАК ДатаРегистратора,
    |    Расчеты.Сумма КАК Сумма,
    |    Расчеты.КОтгрузке КАК КОтгрузке,
    |    Расчеты.КОплате КАК КОплате,
    |    Расчеты.Сторно КАК Сторно,
    |    Расчеты.СвязанныйДокумент КАК СвязанныйДокумент,
    |    Расчеты.ПорядокОперации КАК ПорядокОперации,
    |    Расчеты.ПорядокЗачетаПоДатеПлатежа КАК ПорядокЗачетаПоДатеПлатежа,
    |    Расчеты.ВалютаДокумента КАК ВалютаДокумента,
    |    Расчеты.СтатьяДвиженияДенежныхСредств КАК СтатьяДвиженияДенежныхСредств
    |ПОМЕСТИТЬ РасчетыПоРегистратору
    |ИЗ
    |    ИзмененияВспомогательнойИнформации КАК Изменения
    |    ВНУТРЕННЕЕ СОЕДИНЕНИЕ &Расчеты КАК Расчеты
    |    ПО Изменения.РасчетныйДокумент = Расчеты.Регистратор
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |// ЭТАП 2: Финальное соединение с использованием уже отобранных данных
    |ВЫБРАТЬ
    |    Изменения.РасчетныйДокумент КАК РасчетныйДокумент,
    |    Изменения.ДатаПлановогоПогашения КАК ДатаПлановогоПогашения,
    |    МИНИМУМ(ЕСТЬNULL(Расчеты.Регистратор, Неопределено)) КАК ДокументРегистратор,
    |    МАКСИМУМ(ЕСТЬNULL(Расчеты.СвязанныйДокумент, Неопределено)) КАК СвязанныйДокумент,
    |    МИНИМУМ(ЕСТЬNULL(Расчеты.ПорядокОперации, Неопределено)) КАК ПорядокОперации,
    |    МИНИМУМ(ЕСТЬNULL(Расчеты.ПорядокЗачетаПоДатеПлатежа, Неопределено)) КАК ПорядокЗачета,
    |    МИНИМУМ(ЕСТЬNULL(Расчеты.ВалютаДокумента, Неопределено)) КАК ВалютаДокумента,
    |    МАКСИМУМ(ЕСТЬNULL(Расчеты.СтатьяДвиженияДенежныхСредств, Неопределено)) КАК СтатьяДвиженияДенежныхСредств
    |ИЗ
    |    ИзмененияВспомогательнойИнформации КАК Изменения
    |    ЛЕВОЕ СОЕДИНЕНИЕ РасчетыПоРегистратору КАК Расчеты
    |        ПО Изменения.РасчетныйДокумент = Расчеты.Регистратор
    |        И Изменения.ДатаПлановогоПогашения = НАЧАЛОПЕРИОДА(ВЫБОР КОГДА Расчеты.ДатаПлатежа = ДАТАВРЕМЯ(1,1,1) ИЛИ Расчеты.Сторно
    |                                            ТОГДА Расчеты.ДатаРегистратора
    |                                            ИНАЧЕ Расчеты.ДатаПлатежа
    |                                        КОНЕЦ , ДЕНЬ)
    |        И (Расчеты.Сумма <> 0 ИЛИ Расчеты.КОтгрузке <> 0 ИЛИ Расчеты.КОплате <> 0)
    |ГДЕ
    |    ТИПЗНАЧЕНИЯ(Изменения.РасчетныйДокумент) <> ТИП(Документ.ПервичныйДокумент)
    |СГРУППИРОВАТЬ ПО
    |    Изменения.РасчетныйДокумент,
    |    Изменения.ДатаПлановогоПогашения
    |
    |ОБЪЕДИНИТЬ ВСЕ
    |... // аналогичная структура для ПервичногоДокумента
    |;
    |УНИЧТОЖИТЬ ИзмененияВспомогательнойИнформации";
    
    Запрос.Текст = ТекстЗапроса;
    // ... дальнейшая установка параметров и выполнение запроса
КонецПроцедуры

Проанализируем ситуацию с правами доступа (ТН ВЭД)

Помимо проблем с производительностью, в тех же релизах может возникнуть ошибка «Нарушение прав доступа» при использовании кнопки «Подбор из ТН ВЭД». Разберем, как это связано с архитектурой системы:

В модуле РаботаСОблачнымиКлассификаторами реализована жесткая проверка прав. Система проверяет право Просмотр на конкретные общие команды:

Если у пользователя нет роли, включающей доступ к этим командам, кнопка не будет работать даже при наличии полных прав на сам справочник КлассификаторТНВЭД. Проанализируем решение: необходимо убедиться, что пользователю назначена роль «Использование облачных классификаторов». Она входит в типовые профили «Технолог» и «Ответственный за ведение номенклатуры (дополнительный)».

Практические рекомендации

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

  1. Применить расширение: Используйте приведенный выше код для оптимизации процедуры ЗаполнитьВспомогательнуюИнформацию. Это позволит SQL-серверу выполнять Index Seek по полю Регистратор, что сократит время выполнения запроса с минут до долей секунды.
  2. Обновить статистику СУБД: После массовых изменений или при резком замедлении работы выполните процедуру обновления статистики для таблиц регистров AccumRG (расчеты).
  3. Ревизия аналитики: Посмотрим на структуру данных. Если в системе много «долгоживущих» объектов расчетов (например, один договор, по которому идут тысячи отгрузок годами), это создает дополнительную нагрузку. Рекомендуется использовать детализацию расчетов «По заказам» или «По накладным» для уменьшения объема данных, обрабатываемых в одной транзакции.
  4. Настройка ролей: Проверьте наличие прав на облачные классификаторы, если ваши сотрудники активно используют подбор номенклатуры и кодов ТН ВЭД.

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

← На главную