Заметки эксперта. Расследование длительного выполнения отчета “Движение ТМЦ и затрат в производстве” (1С:ERP 2)

Расследование длительного выполнения отчета

Мы опубликовали в предыдущих двух статьях на наш взгляд интересные и довольно необычные кейсы расследования деградации производительности. Эта статья про случай попроще, но мы считаем, что и он заслуживает вашего внимания. Во-первых, и тут есть существенная проблема с быстродействием. Во-вторых, этот пример показателен тем, что далеко не всегда нужно вообще что-то “переписывать” в конфигурациях 1С. Надеемся, вам будет интересно ;)

 

Инфраструктура исследуемой системы

  • Технологическая платформа 1С:Предприятие 8, версия 8.3.19.1264

  • Конфигурация: 1С:ERP Управление предприятием 2, версия 2.5.6.234

  • Операционная система: Astra Linux Орел 2.12

  • СУБД: Postgres Pro Enterprise 13

  • Размер базы данных: около 500 Гб

  • Количество пользователей: около 2200

 

Проблема

В ходе проведения нагрузочного тестирования прикладного решения “1С:ERP 2” в рамках программы перехода на операционную систему Linux с использованием СУБД Postgres выявлено длительное формирование отчета "Движение ТМЦ и затрат в производстве”.

Если установить в отчете параметры отбора “Период (месяц)” и “Подразделение”, после чего запустить его формирование – это занимает от 40 до 60 минут. Причем, формирование “под нагрузкой” (одновременная работа пользователей) такого отчета у части пользователей завершается с ошибкой “Недостаточно памяти для получения результата запроса к базе данных”.

В остальных случаях результирующий табличный документ пустой – по установленным отборам данных к выводу нет.


Задача

Выявить и устранить причины крайне медленного формирования отчета “Движение ТМЦ и затрат в производстве” в инфраструктуре 1С:ERP 2 / Linux / Postgres.


Расследование

На момент выполнения такого рода расследования, у нас должна быть подключена подсистема БСПОценка производительности”, включен технологический журнал 1С (ТЖ 1С), желательно включить подробное логирование в журнале регистрации 1С (ЖР 1С).

 

Для начала ищем самый длительный замер по ключевой операции формирования этого отчета, полученный подсистемой БСП “Оценка производительности” - запоминаем “Номер сеанса”:

Дата начала замера

Дата окончания замера

Номер сеанса

Длительность, сек.

Пользователь

16.01.2022 16:43:18

16.01.2022 17:23:09

2218

2 390,844

ЭкономистПроизводства_012

 

После чего в ТЖ 1С ищем событие CALL (клиент-серверный вызов), соответствующее данному замеру: ”SessionID=11811(2218)”

22:38.093000-2359346998,CALL,1,Usr=ЭкономистПроизводства_012,SessionID=11811(2218),p:processName=erp,Func=Background job,Module=ДлительныеОперации,Method=ВыполнитьСКонтекстомКлиента,Memory=-858220508,MemoryPeak=15575941249,InBytes=117587968,OutBytes=133120366,CpuTime=336095413


Действительно: вызов длился почти 40 минут

Обращаем внимание на еще один момент: в пике ему потребовалось почти 15 Гб оперативной памяти (свойство MemoryPeak). Это еще одна причина, которая требует расследования (многовато выходит для отчета, который в итоге ничего не выводит).

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

Для анализа ситуации смотрим на запросы, которые выполняются при формировании запроса к базе данных, анализируем события ТЖ 1С  DBPOSTGRS для данного клиент-серверного вызова (сопоставляем по тому же SessionID=11811):

45:09.657000-108177999,DBPOSTGRS,5,process=rphost,p:processName=erp,OSThread=7838,t:clientID=2832,t:applicationName=BackgroundJob,t:computerName=erp02,t:connectID=15586,SessionID=11811,Usr=ЭкономистПроизводства_012,DBMS=DBPOSTGRS,DataBase=erp04\erp,Trans=0,dbpid=27776,Sql="<...>",RowsAffected=42998,Result=PGRES_TUPLES_OK,Context='
ОбщийМодуль.ДлительныеОперации.Модуль : 1063 : ВызватьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);
    ОбщийМодуль.ДлительныеОперации.Модуль : 1073 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыВызова);
        ОбщийМодуль.ОбщегоНазначения.Модуль : 5180 : Выполнить(Текст);
             : 1 : ВариантыОтчетов.СформироватьОтчетВФоне(Параметры[0],Параметры[1])
                ОбщийМодуль.ВариантыОтчетов.Модуль : 2773 : Формирование = СформироватьОтчет(Параметры, Ложь, Ложь);
                    ОбщийМодуль.ВариантыОтчетов.Модуль : 1718 : ОтчетОбъект.СкомпоноватьРезультат(Результат.ТабличныйДокумент, Результат.Расшифровка);
                        Отчет.ПроизводственныеЗатраты.МодульОбъекта : 81 : ПроцессорВывода.Вывести(ПроцессорКомпоновки);'
57:10.549000-720529999,DBPOSTGRS,5,process=rphost,p:processName=erp,OSThread=7838,t:clientID=2832,t:applicationName=BackgroundJob,t:computerName=erp02,t:connectID=15586,SessionID=11811,Usr=ЭкономистПроизводства_012,DBMS=DBPOSTGRS,DataBase=erp04\erp,Trans=0,dbpid=27776,Sql="<...>",RowsAffected=2841404,Result=PGRES_TUPLES_OK,Context='
ОбщийМодуль.ДлительныеОперации.Модуль : 1063 : ВызватьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);
    ОбщийМодуль.ДлительныеОперации.Модуль : 1073 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыВызова);
        ОбщийМодуль.ОбщегоНазначения.Модуль : 5180 : Выполнить(Текст);
             : 1 : ВариантыОтчетов.СформироватьОтчетВФоне(Параметры[0],Параметры[1])
                ОбщийМодуль.ВариантыОтчетов.Модуль : 2773 : Формирование = СформироватьОтчет(Параметры, Ложь, Ложь);
                    ОбщийМодуль.ВариантыОтчетов.Модуль : 1718 : ОтчетОбъект.СкомпоноватьРезультат(Результат.ТабличныйДокумент, Результат.Расшифровка);
                        Отчет.ПроизводственныеЗатраты.МодульОбъекта : 81 : ПроцессорВывода.Вывести(ПроцессорКомпоновки);'
04:07.978000-292160999,DBPOSTGRS,5,process=rphost,p:processName=erp,OSThread=7838,t:clientID=2832,t:applicationName=BackgroundJob,t:computerName=erp02,t:connectID=15586,SessionID=11811,Usr=ЭкономистПроизводства_012,DBMS=DBPOSTGRS,DataBase=erp04\erp,Trans=0,dbpid=28219,Sql="<...>",RowsAffected=3023307,Result=PGRES_TUPLES_OK,Context='
ОбщийМодуль.ДлительныеОперации.Модуль : 1063 : ВызватьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);
    ОбщийМодуль.ДлительныеОперации.Модуль : 1073 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыВызова);
        ОбщийМодуль.ОбщегоНазначения.Модуль : 5180 : Выполнить(Текст);
             : 1 : ВариантыОтчетов.СформироватьОтчетВФоне(Параметры[0],Параметры[1])
                ОбщийМодуль.ВариантыОтчетов.Модуль : 2773 : Формирование = СформироватьОтчет(Параметры, Ложь, Ложь);
                    ОбщийМодуль.ВариантыОтчетов.Модуль : 1718 : ОтчетОбъект.СкомпоноватьРезультат(Результат.ТабличныйДокумент, Результат.Расшифровка);
                        Отчет.ПроизводственныеЗатраты.МодульОбъекта : 81 : ПроцессорВывода.Вывести(ПроцессорКомпоновки);'


Видим, что два запроса выполняются долго - в листинге выше: 720529999 мкс второй запрос, 292160999 мкс третий запрос. Кроме этого, они еще и возвращают в итоге около 3 миллионов строк каждый: RowsAffected=2841404 во втором запросе, RowsAffected=3023307 в третьем запросе.

Это явно избыточная нагрузка на СУБД. К тому же выходит, что фильтрация осуществляется уже после получения данных из базы, ведь результат, как мы помним - у пользователей все равно пустой.


Переходим к самому отчету в конфигурации 1С.

Помним: в варианте отчета, вызывающем проблему, отбор устанавливается по периоду и по подразделению.

Открываем настройки схемы компоновки данных (СКД) для данного отчета и видим: отбор по подразделению указан не для отчета, а в отдельных группировках.

Открыть оригинальный размер

Такая настройка СКД приводит к избыточному чтению данных из СУБД: из базы данных сначала выбираются все данные, без отбора по подразделению. И только после этого компоновщик СКД для каждой группировки накладывает отбор по подразделению.

 

Решение 

Проанализировав полученные выше данные по работе 1С с СУБД в контексте этого отчета и структуру его СКД, делаем вывод: основной отбор по подразделению можно перенести в сам отчет, не нарушая логику его работы. Вот так:

Открыть оригинальный размер

То есть условия в отборе для отчета будут применяться сразу, что ожидаемо снизит нагрузку на СУБД, минимизируя получаемые оттуда данные. 

Применяем изменения в конфигурации 1С и проверяем формирование отчете в рамках следующей итерации нагрузочного тестирования:

52:05.794000-1516999,DBPOSTGRS,5,process=rphost,p:processName=erp,OSThread=4120,t:clientID=253,t:applicationName=BackgroundJob,t:computerName=erp01,t:connectID=2740,SessionID=2298,Usr=ЭкономистПроизводства_012,DBMS=DBPOSTGRS,DataBase=erp04\erp,Trans=0,dbpid=30344,Sql="<...>",RowsAffected=0,Result=PGRES_TUPLES_OK,Context='
ОбщийМодуль.ДлительныеОперации.Модуль : 1063 : ВызватьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);
    ОбщийМодуль.ДлительныеОперации.Модуль : 1073 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыВызова);
        ОбщийМодуль.ОбщегоНазначения.Модуль : 5180 : Выполнить(Текст);
             : 1 : ВариантыОтчетов.СформироватьОтчетВФоне(Параметры[0],Параметры[1])
                ОбщийМодуль.ВариантыОтчетов.Модуль : 2773 : Формирование = СформироватьОтчет(Параметры, Ложь, Ложь);
                    ОбщийМодуль.ВариантыОтчетов.Модуль : 1718 : ОтчетОбъект.СкомпоноватьРезультат(Результат.ТабличныйДокумент, Результат.Расшифровка);
                        Отчет.ПроизводственныеЗатраты.МодульОбъекта : 81 : ПроцессорВывода.Вывести(ПроцессорКомпоновки);'                        
52:22.199000-15617999,DBPOSTGRS,5,process=rphost,p:processName=erp,OSThread=4120,t:clientID=253,t:applicationName=BackgroundJob,t:computerName=erp01,t:connectID=2740,SessionID=2298,Usr=ЭкономистПроизводства_012,DBMS=DBPOSTGRS,DataBase=erp04\erp,Trans=0,dbpid=30668,Sql="<...>",RowsAffected=0,Result=PGRES_TUPLES_OK,Context='
ОбщийМодуль.ДлительныеОперации.Модуль : 1063 : ВызватьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);
    ОбщийМодуль.ДлительныеОперации.Модуль : 1073 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыВызова);
        ОбщийМодуль.ОбщегоНазначения.Модуль : 5180 : Выполнить(Текст);
             : 1 : ВариантыОтчетов.СформироватьОтчетВФоне(Параметры[0],Параметры[1])
                ОбщийМодуль.ВариантыОтчетов.Модуль : 2773 : Формирование = СформироватьОтчет(Параметры, Ложь, Ложь);
                    ОбщийМодуль.ВариантыОтчетов.Модуль : 1718 : ОтчетОбъект.СкомпоноватьРезультат(Результат.ТабличныйДокумент, Результат.Расшифровка);
                        Отчет.ПроизводственныеЗатраты.МодульОбъекта : 81 : ПроцессорВывода.Вывести(ПроцессорКомпоновки);'
52:25.135000-2789999,DBPOSTGRS,5,process=rphost,p:processName=erp,OSThread=4120,t:clientID=253,t:applicationName=BackgroundJob,t:computerName=erp01,t:connectID=2740,SessionID=2298,Usr=ЭкономистПроизводства_012,DBMS=DBPOSTGRS,DataBase=erp04\erp,Trans=0,dbpid=30562,Sql="<...>",RowsAffected=0,Result=PGRES_TUPLES_OK,Context='
ОбщийМодуль.ДлительныеОперации.Модуль : 1063 : ВызватьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);
    ОбщийМодуль.ДлительныеОперации.Модуль : 1073 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыВызова);
        ОбщийМодуль.ОбщегоНазначения.Модуль : 5180 : Выполнить(Текст);
             : 1 : ВариантыОтчетов.СформироватьОтчетВФоне(Параметры[0],Параметры[1])
                ОбщийМодуль.ВариантыОтчетов.Модуль : 2773 : Формирование = СформироватьОтчет(Параметры, Ложь, Ложь);
                    ОбщийМодуль.ВариантыОтчетов.Модуль : 1718 : ОтчетОбъект.СкомпоноватьРезультат(Результат.ТабличныйДокумент, Результат.Расшифровка);
                        Отчет.ПроизводственныеЗатраты.МодульОбъекта : 81 : ПроцессорВывода.Вывести(ПроцессорКомпоновки);'
52:25.333001-25484999,CALL,1,Usr=ЭкономистПроизводства_012,SessionID=2298(766),p:processName=erp,Func=Background job,Module=ДлительныеОперации,Method=ВыполнитьСКонтекстомКлиента,Memory=-184943301,MemoryPeak=14490779,InBytes=0,OutBytes=0,CpuTime=5387584


Видим, что отбор сразу применился на уровне запроса к базе данных (RowsAffected=0). Потребление памяти при этом снизилось до 15 Мб (MemoryPeak=14490779). 

Отчет сформировался за 30 секунд:

Дата начала замера

Дата окончания замера

Номер сеанса

Длительность, сек.

Пользователь

24.01.2022 12:51:59

24.01.2022 12:52:29

766

29,804

ЭкономистПроизводства_012

 

Таким образом, без серьезной корректировки отчета, не углубляясь в его бизнес-логику и не меняя её, мы ускорили формирование отчета почти в 80 раз. Кроме этого, избавились от высокого потребления памяти процессами сервера, что порождало ошибку недостатка памяти для получения результата запроса и отображению пользователю.

 

 

Впервые опубликовано на портале Инфостарт: https://infostart.ru/1c/articles/1662406/


Репост

Свяжитесь с нами

119435 г. Москва, ул. Малая Пироговская, 16
Контакты
Нажимая кнопку "Начать сотрудничество" я принимаю условия Пользовательского соглашения и согласен на обработку Персональных данных
Связаться с нами

Заполните форму ниже и наши специалисты свяжутся с вами в ближайшее время

Удобное время для звонка
  • 10:00 - 12:00
  • 12:00 - 14:00
  • 14:00 - 16:00
  • 16:00 - 18:00
  • 18:00 - 19:00
Время московское
Отвечаем с понедельника по пятницу
Нажимая кнопку "Связаться с нами" я принимаю условия Пользовательского соглашения и согласен на обработку персональных данных