Некоторые замечания по ускорению работы управляемых форм

12.02.14

База данных - HighLoad оптимизация

Началось все с того, что к нам обратился клиент для проведения аудита производительности. Были жалобы на общую производительность системы, а также были обозначены отдельные конкретные операции, которые выполняются долго. О некоторых этих операциях, и о том, как их удалось ускорить и хочу рассказать.

Хочу поделиться своим опытом с сообществом. Надеюсь, он будет интересен и полезен разработчикам 1С, которые делают свои приложения на управляемых формах.

Началось все с того, что к нам обратился клиент для проведения аудита производительности. Были жалобы на общую производительность системы, а также были обозначены отдельные конкретные операции, которые выполняются долго. О некоторых этих операциях, и о том, как их удалось ускорить и хочу рассказать.

Операция 1. Рабочее место менеджера по отгрузке

 

Есть обработка на управляемых формах, в которой основной элемент – это динамический список.  Данная обработка является критичной для бизнеса, т.к. используется она довольно часто и ее медленная работа влияет на скорость всего бизнес-процесса отгрузки.

Медленно выполняется операция по открытию и обновлению этого динамического списка. Среднее время выполнения этой операции у пользователя с включенным RLS составляло примерно 60 секунд. Данное поведение стабильно воспроизводилось и на копии базы. При работе без RLS скорость увеличивалась до 40 секунд.

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

 

Также этот второй список получал данные даже дольше первого.

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

В тексте второго запроса нашли возможность оптимизации запроса. В тексте использовалось разыменование поля составного типа. Используя конструкцию «ВЫРАЗИТЬ» удалось ускорить операцию открытия списка формы, однако незначительно.

Текст до изменения:

 

После:

 

Список до сих пор открывался долго.

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

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

Тогда решили заменять текст запроса на «пустышку», и устанавливать его назад, при выборе страницы. Тогда при открытии формы, данные для второго дин.списка не будут получаться до тех пор, пока мы не откроем эту закладку.

 

 

 

В итоге, скорость открытия данной формы возвросла после доработок с 50-60 секунд до 7-10 при проверки открытия пользователем с ограничением по RLS.
Операция 2. Вывод характеристик при подборе товара

 

Обработка подбора, при выборе номенклатуры, и двойном щелчке на ней, обработка «проваливалась» в выбор остатков по характеристике этой номенклатуры.

 

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

 

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

 

При анализе кода обработки, мы увидели возможность заменить контекстный вызов функции «ВывестиХарактеристики» на внеконтекстный. Это позволило сократить объем передаваемого трафика между клиентом и сервером и на наших замерах позволило добиться улучшения в два раза, с 5-6 секунд до 2-3.

Операция 3. Динамический список с остатками

Данная операция была определена с помощью сервиска querytj. Она была в топе долгих запросов на первом месте. Вот некоторые данные о самых долгих операциях выполнения данного запроса. Открытие списка доходило до 500 секунд!

 

Определив по контексту место данного запроса, определили его текст в терминах 1С.

 

Оказалось, что это довольно-таки простой запрос. Соединение с  виртуальной таблицей остатков не должно было вызывать проблем, т.к. этот запрос должен был соединяться с таблицей текущих остатков. Также по логике работы текущие остатки должны быть незначительными, т.к. заказы должны закрываться, и в остатках должны оставаться только незакрытые строки.

Однако он выполнялся долго. Просматривая текст запроса, мы нашли участок, приводящий к замедлению. Это было как раз обращение к таблице итогов регистра «ЗаказыНаПеремещение».

 

«Узкое место»

 

Причиной этого удалось быстро найти. Это были нулевые итоги в этой таблице. Так из 238 тысяч записей текущих итогов, 236 тысяч были нулевыми. Это очень замедляло выполнение данного запроса. Подробнее об этом вопросе рассказано тут.

 


Для решения этой проблемы нужно было сделать пересчет итогов. Так до пересчёта итогов – мы наблюдали долгое открытие списка документов Перемещение товаров, иногда задержка составляла более 60 секунд. Но после пересчета итогов, данный список стал открываться за время менее секунды.

Выводы:

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

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

См. также

HighLoad оптимизация Программист Платформа 1С v8.3 Бесплатно (free)

Метод очень медленно работает, когда параметр приемник содержит намного меньше свойств, чем источник.

06.06.2024    9260    Evg-Lylyk    61    

44

HighLoad оптимизация Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Анализ простого плана запроса. Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы.

13.03.2024    5097    spyke    28    

49

HighLoad оптимизация Программист Платформа 1С v8.3 Бесплатно (free)

Оказывается, в типовых конфигурациях 1С есть, что улучшить!

13.03.2024    7573    vasilev2015    20    

42

HighLoad оптимизация Инструменты администратора БД Системный администратор Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих запросов на sql, ожиданий, конвертация запроса в 1С и рекомендации, где может тормозить.

2 стартмани

15.02.2024    12422    241    ZAOSTG    80    

115

HighLoad оптимизация Системный администратор Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Принимать, хранить и анализировать показания счетчиков (метрики) в базе 1С? Почему бы нет? Но это решение быстро привело к проблемам с производительностью при попытках построить какую-то более-менее сложную аналитику. Переход на PostgresSQL только временно решил проблему, т.к. количество записей уже исчислялось десятками миллионов и что-то сложное вычислить на таких объемах за разумное время становилось все сложнее. Кое-что уже практически невозможно. А что будет с производительностью через пару лет - представить страшно. Надо что-то предпринимать! В этой статье поделюсь своим первым опытом применения СУБД Clickhouse от Яндекс. Как работает, что может, как на нее планирую (если планирую) переходить, сравнение скорости работы, оценка производительности через пару лет, пример работы из 1С. Все это приправлено текстами запросов, кодом, алгоритмами выполненных действий и преподнесено вам для ознакомления в этой статье.

1 стартмани

24.01.2024    5669    glassman    18    

40

HighLoad оптимизация Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Встал вопрос: как быстро удалить строки из ТЗ? Рассмотрел пять вариантов реализации этой задачи. Сравнил их друг с другом на разных объёмах данных с разным процентом удаляемых строк. Также сравнил с выгрузкой с отбором по структуре.

09.01.2024    14018    doom2good    49    

71
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. speshuric 1338 12.02.14 15:25 Сейчас в теме
Статья в целом неплохая, но вот следующая цитата у меня вызывает вопросы:
В динамические списки не стоит задавать сложные запросы, т.к. он читает данные курсорным способом (выбирая данные порционно), а на сложных запросах, в которых участвует много таблиц, чтение курсорным способом может не быть выполнена оптимально оптимизатором СУБД.

Судя по ТЖ и по трассам 1С 8 курсоры вообще-то не использует. Данные для форм выбираются достаточно неприятно для SQL Server, порционно, но не курсором. Если запрос строится платформой по объекту метаданных, то обычно запрос выглядит примерно так:
ВЫБРАТЬ ПЕРВЫЕ %СколькоТоСтрок%
    Поле1, Поле2, ... ПолеN
ИЗ
    %КучкаСоединений-StarJoin%
ГДЕ
    УпорядоченноеПоле1 > &УпорядоченноеПоле1НачалаСписка ИЛИ
    УпорядоченноеПоле1 = &УпорядоченноеПоле1НачалаСписка И УпорядоченноеПоле2 > &УпорядоченноеПоле2НачалаСписка ИЛИ
    УпорядоченноеПоле1 = &УпорядоченноеПоле1НачалаСписка И УпорядоченноеПоле2 = &УпорядоченноеПоле2НачалаСписка И ... УпорядоченноеПолеN > &УпорядоченноеПолеNНачалаСписка
УПОРЯДОЧИТЬ ПО УпорядоченноеПоле1, УпорядоченноеПоле2, ... УпорядоченноеПолеN 
Показать

Основная проблема тут не только соединения, а чаще условие "ГДЕ". Даже если есть индекс по всем значениям упорядочнивания, начиная с 4-5 полей SQL часто перестаёт понимать, что это всего лишь "выводи записи начиная с ..." и, если первое поле упорядочнивания не даёт достаточно селективного отбора запрос либо уходит в сканы, либо в паралеллизм, либо и то и другое.
В принципе подход 1С понятен:
1. Не использовать курсоры, которые потребуют хранения состояния и сервер 1С перестаёт быть stateless
2. Реализацией на "честном" SQL можно покрыть больше СУБД.
Способы борьбы тоже яснее ясного: отказываться от лишних сортировок, строить индексы "с доп. упорядочиванием"

Ну а если основой запроса является еще и динамический список, то там есть другие моменты: 1С не может гарантировать, что у запроса есть какой-то "уникальный ключ". И поэтому поступает как может. Выбирает сначала первые 1000, потом первые 2000, потом первые 3000 и т.д. Легче всего убедиться в этом, трассируя динамическую форму с таблицей остатков.

Здесь производительность явно принесена в жертву универсальности и авторов платформы в этом можно понять, а нам надо учитывать эту специфику. Курсорность тут ни при чем.
Irwin; logarifm; adhocprog; milanse; AllexSoft; agrustny; amon_ra; JesteR; theshadowco; Evil Beaver; sunshineuee; Vladuha; artbear; dmpas; dour-dead; alex_sayan; xzorkiix; Sitex; vlad.frost; slavap; fancy; Bronislav; rzabolotin; awk; malikov_pro; kiruha; tormozit; AHDP; cleaner_it; +29 Ответить
2. maddy 20 12.02.14 15:58 Сейчас в теме
В последнем запросе левое соединение стоит заменить внутренним.
По фильтру документы по которым нет остатков отсекаются, результат будет тот же но должен быть быстрее.
talych; artbear; PowerBoy; cleaner_it; +4 Ответить
3. bonv 1560 12.02.14 18:25 Сейчас в теме
Мы решили отключить этот список, и включать его только при открытии пользователем этой закладки. Попробовали сначала отключать его с помощью сброса флажка видимость, однако это не помогло. Запрос все равно получал данные, даже не смотря на то, что список был невидим.


В 8.3 это должны были починить. Сам не проверял.
5. ivanov660 4577 12.02.14 23:31 Сейчас в теме
(3) doxflow, ага в 8.3 есть такое исправление. Сами столкнулись когда пробовали в УТ 11 не последней версии посмотреть работоспособность - старая форма подбора товаров упала (там есть переключения видимости между списками номенклатуры и характеристик, но данные запрашиваются с обоих списков).
4. B2B 274 12.02.14 23:29 Сейчас в теме
По-моему, использовать конструкции типа ТИПЗНАЧЕНИЯ(...) = ТИП(...) абсолютно неправильно. Я бы переписал запрос примерно так:
ГДЕ
    Статусы.Документ ССЫЛКА Документ.ОтборочнаяВедомость
    И Статусы.Документ.Распоряжение ССЫЛКА Документ.ЗаказНаПеремещение
Irwin; suarez55; EdmundoAlvares; ghostaz; Oleg_nsk; wunderland; Vladuha; kuza_87; pt_olga; kirillkr; burlakov; Nefertary; west__; ivanov660; +14 Ответить
6. ivanov660 4577 12.02.14 23:41 Сейчас в теме
(4) B2B, а вот функции Выразить(поле как тип) довольно разумно, т.к. сокращает количество неявно присоединяемых таблиц
7. Bukaska 140 13.02.14 00:33 Сейчас в теме
(6) ivanov660, Да ВЫРАЗИТЬ - оно почти везде нужно, особенно когда дело касается регистраторов. Так как без данного оператора мы просто вешаем БД)))
10. xzorkiix 35 13.02.14 17:13 Сейчас в теме
(7) Bukaska, а где можно посвятиться по поводу Выразить в запросах?
11. indigo_ 13.02.14 17:39 Сейчас в теме
(10) xzorkiix,
где можно посвятиться

или Вы имели в виду "просветиться" ?
16. speshuric 1338 14.02.14 10:26 Сейчас в теме
(10)
Про "выразить" в запросах по составным типам
19. kuza_87 28 19.02.14 06:29 Сейчас в теме
(4) B2B, Ты прав. Замер производительности не даст соврать!
20. kuza_87 28 19.02.14 06:34 Сейчас в теме
(4) B2B, Сейчас сделал поиски текста запросов с "ТипЗначения()=Тип()" по новейшей конфигурации 1с "Документооборот" и пришел в ужас. 1с-вцы повсюду используют данную функцию!!! Хотя сами больше всех орут про производительность и валят народ на экзаменах при малейших косяках
ITEkb; bulpi; +2 Ответить
22. ITEkb 26.02.14 08:24 Сейчас в теме
(20) kuza_87, Те же действия сделал.. Меня не валили. Но не знал про этот косяк. Потому плюс.
21. Andreynikus 1378 20.02.14 12:49 Сейчас в теме
(4)B2B,
Правильнее делать
ТипЗначения()=Тип()
или
Статусы.Документ ССЫЛКА Документ.ОтборочнаяВедомость
И ВЫРАЗИТЬ(Статусы.Документ КАК Документ.ОтборочнаяВедомасть).Распоряжение ССЫЛКА Документ.ЗаказНаПеремещение


Между этими способами нет никакой разницы, запрос на языке SQL будет одинаковым, а условие примет следующий вид: WHERE (T1._RecorderTRef = @P2) AND (T2._Fld781_TYPE = 0x08 AND T2._Fld781_RTRef = @P3)
Это условие довольно простое и оптимизатор может легко его обработать и подобрать оптимальный план.

НО, если написать так как написано в комментарии (4)

Статусы.Документ.Распоряжение ССЫЛКА Документ.ЗаказНаПеремещение

т.е. обратится в условии через точку к полю составного типа, то условие примет вид:
WHERE (T1._RecorderTRef = @P2) AND (CASE WHEN T1._RecorderTRef = @P3 THEN T2._Fld781_TYPE ELSE CAST(NULL AS BINARY(1)) END = 0x08 AND CASE WHEN T1._RecorderTRef = @P4 THEN T2._Fld781_RTRef ELSE CAST(NULL AS BINARY(4)) END = @P5)

В моем случае это привело к сканированию таблицы Т1 и как следствие количество логических чтений выросло в 4 раза, запрос стал работать медленнее. Оптимизатор просто не смог использовать индекс по полю T1._RecorderTRef.

Следовательно лучше использовать ТипЗначения()=Тип() или в условии использовать ВЫРАЗИТЬ при обращении через точку к полю составного типа. Оба этих приема приводят к одинаковому тексту SQL запроса.
alex_4x; talych; Puk2; vbuots; putdv; +5 Ответить
8. DoctorRoza 13.02.14 08:12 Сейчас в теме
Отмечусь, нужно со статьей по-внимательней ознакомиться! :)
9. burlakov 83 13.02.14 14:03 Сейчас в теме
а если бы запрос переписали по человечески - без вложенных запросов, то было бы еще быстрее. и никакого профайлера не надо.
12. AllexSoft 13.02.14 18:22 Сейчас в теме
Неплохая статья... в целом как обмен опытом то плюс... опять же вопрос к Доржи, когда уже будут Кейсы для внедренцев\разработчков... а то статьи разбросаны, потом фиг найдешь (
13. Evgen.Ponomarenko 568 13.02.14 21:58 Сейчас в теме
(12) AllexSoft,
Ага... всего-то требуется сделать "человеческое" управление функциями "Мои рекомендации","Мои загрузки" и "Мои комментарии".
14. asved.ru 36 14.02.14 07:18 Сейчас в теме
В порядке работы допущена, я бы сказал, методическая ошибка: исследования должны проводиться на оптимальном состоянии БД. Что это значит: итоги пересчитаны, индексы и статистики актуальны, регламентные операции по поддержке такого состояния автоматизированы.

Приведение БД в оптимальное состояние не требует трудозатрат высококвалифицированного специалиста и может существенно сэкономить его трудозатраты на этапе анализа и решения проблем: в вашем случае работы по п.3 вообще бы не потребовались.

agrustny; +1 Ответить
15. gaglo 14.02.14 10:23 Сейчас в теме
А что за конфигурация исследовалась, если не секрет? Или хоть общими словами: чья-то полностью самописная, или стандартная, или стандартная, но доработанная по методу Франкенштейна?
agrustny; +1 Ответить
17. Stas-ch 35 17.02.14 10:48 Сейчас в теме
(15) gaglo, Судя по скринам это УТ-11.
18. gaglo 17.02.14 10:57 Сейчас в теме
(17) Ну и интересно же, что эти тормозные операции 1 и 2? Сразу были в УТ-11 такими или же их некто "доработал"?
23. GROOVY 2510 26.02.14 13:34 Сейчас в теме
Про динамический список: А условие в левом соединении ...Остатки(, {Товар КАК Ссылка})... не решит проблему выбора левых пустых остатков?
24. StaticUnsafe 07.03.14 10:32 Сейчас в теме
Спасибо за статью. Были проблемы с избытком динамических списков на УФ. До трех на одной форме со сложными запросами. Благодаря советам удалось оптимизироваться.
25. Sasha255n 14.03.14 13:04 Сейчас в теме
Да соглашусь с предыдущими ораторами не понятно что за конфигурация
26. vermouth 26.07.14 15:44 Сейчас в теме
А условие из ГДЕ нельзя перенести в условие виртуальной таблицы РегистрНакопления.ЗаказыНаПеремещение.Остатки() ??
27. sanfoto 502 05.10.14 14:20 Сейчас в теме
(0) rzabolotin,

В итоге, скорость открытия данной формы возвросла после доработок с 50-60 секунд до 7-10 при проверки открытия пользователем с ограничением по RLS.


Кстати вставлю свой пример про (псевдо) "Управляемые формы" : была подобная проблема на моноблоках обработка открывалась от 60 сек до 3 минут....
в отладчике смотрели запрос выполняется быстро не более 1сек. (На обычном/не древнем десктопе форма открывалась несколько секунд).
Решили что проблема с отрисовкой формы... видюха на моноблоке слабая....ничего не поделаешь.

Но помог случай)) сломался на моноблоке HDD (вечером) .... заменить было нечем - новый привезут еще когда.... и как раз у нас были в отделе несколько SSD .... взяли.. поставили... накатили OS +1с
и о чудо обработка открывалась не более 3 сек!!!!! вот такой "тонкий клиент" однако... якобы совсем для слабого оборудования предназначен... угу ага)))
28. Bukaska 140 06.10.14 11:21 Сейчас в теме
(27) sanfoto, Ну так.. 1с же беспокоит дисковое пространство. Чем быстрее диск, тем более быстрее открываются данные)))

о чудо обработка открывалась не более 3 сек!!!!! вот такой "тонкий клиент" однако... якобы совсем для слабого оборудования предназначен... угу ага)))

Если говорят про слабое звено, то все равно нужно смотреть посильнее звено.. Это же все таки программа)))
29. AllexSoft 06.10.14 11:40 Сейчас в теме
была проблема из запроса заполнялась таблица значений на форме.. Таблица заполнялась очень долго, полезли смотреть почему, думали запрос тормозной (а он реально большой был). Нет, запрос отрабатывал быстро, а вот с передачей с сервера на клиент или с отрисовкой таблицы были какие то тормоза ужасные. 1000позиций всего лишь - отображалось минут 5! Диски SSD - база небольшая, локальная, просто для теста взяли. Победить так и не удалось (
30. Tanis 24.12.14 14:05 Сейчас в теме
Спасибо большое!
Но возник вопрос.
Составляю форму реквизитов, ставлю запрос. А вот наименование никак не выводит. Как его получить в эту нарисованную форму?
Спасибо!
31. Tanis 24.12.14 16:08 Сейчас в теме
Если правильно понял, то ни строка ни ссылка не передается. :-(
Либо что-то изначально поставил не так.
Можете чуть подробнее подсказать, где настроить и как основные элементы чтоб использовать это условие?
Оставьте свое сообщение