В данной статье коснемся проблемной стороны разработки кода. Посмотрим на примеры кода и ситуаций, которые могут привести или приводят к проблемам производительности. Диалог будем вести от «простых» ситуаций к сложным.
В следующей статье проведем анализ проблем с использованием профайлера и плана запросов, т.е. посмотрим как это все выглядит со стороны SQL сервера.
Думаю, что актуально для специалистов начального уровня и среднего, а сеньоры могут дополнить примерами из своего опыта. Господа сеньоры возможно для вас это банально и стандартно, но для меня когда я начинал работать с управляемыми формами и платформой 1С - это бы очень пригодилось, поэтому давайте общаться в конструктивном диалоге, спасибо.
Коллеги делитесь в комментариях описанием Ваших вариантов/ситуаций, будем рады почитать, спасибо!
О чем поговорим?
I) Разбор ситуаций
Типы ошибок.
- Проблемы знаний – привносит нам проблемы, связанные с неопытностью разработчика. Иногда вместо правильного решения мы можем увидеть брутфорс и т.п. Свойственно в основном разработчику начального уровня.
Исключение таких ошибок решается повышением квалификации специалистов. Список мероприятий:- курсы,
- патронаж/наставничество,
- тех-часы,
- самообучение,
- код-ревью (обзор-кода),
- парное кодирование (очень мощная практика, но дорогая тратится время сразу двух специалистов).
- другие.
- Ошибки кодирования – ошибки, допускаемые любыми специалистами. Это могут быть опечатки, проблемы копирования/вставки или другие подобного рода.
Мероприятия для их отлова:- проверка статическим анализатором 1С,
- запуск тестов (тестирование),
- обзор-кода.
- Быстрое решение – свойственно создание костыльного, не масштабируемого, плохого решения, в котором в угоду скорости (нужно было вчера) приносится в жертву качество. В результате в дальнейшем сталкиваемся с обрастанием костылями и проблемами в работе. Эта ошибка всегда увеличивает технический долг.
Могут быть исправлены процедурой, которая называется - рефакторинг кода. - Архитектурные – самые страшные ошибки. Исправление этих ошибок самый трудоемкий процесс иногда может означать полностью переделку системы. Если система модульная, то исправление еще возможно в обозримые сроки.
Недопущение:- проведение архитект-ревью,
- заимствование решений из проверенных конфигураций,
- мозговой штурм,
- консультаций и технический аудит опытными специалистами.
1. Храним файлы в реквизитах объекта
Постановка задачи:
- Заказчик попросил добавить картинку – фотографию пользователя и/или дополнительное изображение товара в номенклатуру.
Реализация:
- Добавляем реквизит с типом «Хранилище Значений» и храним картинку в объекте.
Проблема:
- Картинки могут быть большие и при обращении к данным объекта через точку (это тоже плохо) или при открытии карточки объекта мы будем каждый раз перекачивать мегабайты изображений.
Реализация данного решения свойственна новичку в разработке.
Решение:
- Откатываем механизм хранения файлов в объекте.
- Используем из БСП подсистему файлов (ссылка на ИТС БСП подсистема файлов):
- Добавляем новый справочник «Пользователи Присоединенные Файлы»;
- Добавляем реквизит ссылку в самом справочнике;
- Добавляем обвязку подсистемы.
Мероприятия:
- Выполнять код-ревью решений
- Контролировать работу новичка, дать ему наставника, парное программирование и т.п.
- Проводить обсуждения в команде вариантов реализации
2. Забыли добавить условие отбора
Что происходит:
- О проблеме сообщили, когда накопился большой объем данных более 200 тысяч документов.
- При выводе на печать состава товаров документа «Маршрутный лист» время печати возросло с 2 до 40 секунд.
Проблема:
- В печатной форме при формировании таблицы данных на печать забыли добавить условие на отбор (ссылку на массив документов) из-за этого впустую используются лишние ресурсы. На рисунке или текстовом блоке приведен пример кода с ошибкой.
Решение:
- Добавили условие отбора ("ТаблицаВыходныеИзделия.Ссылка В (&МассивСсылок)"). Результат решения приведен на рисунке ниже.
Мероприятия:
- Проверять длительные запросы.
- Выполнять тесты
- Выполнять обзор-кода (новый чек поинт).
3. Используем неоптимальный поиск при обработке данных в циклах
Постановка задачи:
- Заказчик попросил создать обработку загрузки товаров из файла (Excel) в документы ввода остатков (данных больше 1000 позиций)
Подобный код часто используется в обработках загрузки данных, различных программных обработках данных (удивила конфигурация УХ, из-за которой и появился этот пункт)
Быстрый код:
- Создали процедуру для обработки данных, для того чтобы учесть уже найденные элементы была создана таблица для хранения кеша найденных данных данных.
Проблема:
- Поиск по таблице медленный при больших объемах данных. Для разового поиска пойдет, но для цикла выглядит ужасно.
Решение:
- Требуется добавить индекс на поля участвующие в отборе ("ТаблицаКеша.Индексы.Добавить("НоменклатураСтрокой");")
- Или использовать тип "Соответствие" для поиска (хешированную таблицу) кешированных данных
Мероприятия:
- Обзор-кода
- Ведем базу знаний
- Обсуждаем хорошие практики
4. Используем директиву &НаСервереБезКонтекста
Что происходит:
- Обрабатываем большой объём данных;
- При работе на управляемой форме происходят длительные «подвисания» при попытке выбрать склад, изменить значение элемента или других действий с реквизитами.
Проблема:
- Между клиентом и сервером передается большой объем данных десятки тысяч и более;
- Процесс сериализации и десериализации данных на форме начинает оказывать существенное влияние на процесс работы.
Решение:
- Для вызовов серверных расчетов с клиента необходимо использовать операнд «&НаСервереБезКонтекста»;
- При работе на управляемой форме надо максимально снижать количество вызовов с клиента контекстных серверных;
- Стараться работать с меньшим объемом данных – используйте фильтры;
- То, что можете получить на сервере и нужно на сервере – получайте и обрабатывайте там;
- Измените, обдумайте снова логику приложения.
Пример варианта исправления кода приведен ниже. Как вы можете убедиться, то создание правильного кода в данном случае достигается тратой пары секунд и дописыванием двух слов «без контекста».
Мероприятия:
- Обзор кода
- Чек лист для обзора кода
- Читаем статьи про то как работает клиент-серверное взаимодействие
5. Используем директиву &НаКлиентеНаСервереБезКонтекста
Что происходит:
- Иногда в процессе работы на управляемых формах требуется использовать функцию или процедуру, которая выполняет одинаковые функции на клиенте или сервере одновременно.
Реализация:
- Создаем две функции, которые на клиенте и сервере и называем "ФункцияНаКлиенте" и "ФункцияНаСервере".
- Создаем одну функцию, но на сервере
Проблемы:
- Возможно дублирование кода, если реализовать две отдельных функции
- Выполнение лишних передач данных между клиентом и сервером, т.к. используем "НаСервере"
Решение:
- Создаем одну функцию с директивой "&НаКлиентеНаСервереБезКонтекста"
6. Отсутствие индекса по соединяемым полям в пакетных запросах
Что происходит:
- По результатам анализа длительных запросов по отчету конфигурации «Мониторинг производительности» было выявлено необычное, плавающее появление длительных запросов регламентного задания.
- Нормальное время выполнения 2-3 секунды
- Аномалия выполнялась 120-600 секунд.
Проблема:
- План запросов может выбираться не оптимальный
- Длительное время выполнения загружает сервер
- Мешает пользователям (особенно в высоконагруженных базах)
- Чем больше активность, тем значительнее влияние
Решение:
- Индексируем все поля, которые в пакетных запросах участвуют в соединениях, условиях/отборах.
По факту вы можете возразить, что будет потрачено лишнее время на данную процедуру. Но в большинстве случаев – это доли секунды и со временем основного запроса несопоставимы. Зато у вас появляется стабильность. В следующей статье мы рассмотрим как выглядят изменения в плане построения запросов для разных случаев.
В данном случае требуется добавить для временной таблицы ВтСклады описание индексирования "ИНДЕКСИРОВАТЬ ПО Склад".
7. Условия по измерениям вне виртуальных таблиц
Что происходит:
- Разработчик не соблюдает стандарты разработки и выполняет отборы вне виртуальных таблиц «Остатки», «Обороты», «Остатки и Обороты», «Срез Последних» и др.
- Подход тяп ляп и в «боевую» базу.
P.S. На всех собеседованиях, я тем или иным образом проверяю квалификацию разработчиков задавая косвенные и наводящие вопросы про знания оптимальных вещей.
Проблема:
- Такой подход необоснованно перегружает оборудование;
- Плохой стиль.
Решение:
- Перенести отборы в виртуальную таблицу;
- Следовать стандартам и рекомендациям в разработке на платформе 1С.
Мероприятия:
- Отправить джуна на курсы
- Обзор-кода
- Просмотр длительных запросов
8. Используем объектную модель, а не запросную
Пример:
- При проведении заказа клиента в модуле объекта «При Записи» выполняем проверку наличия в договоре признака «Лимитный»
Проблема:
- Права доступа (у пользователя может не быть доступа к части реквизитов объекта)
- Получается весь объект целиком (это документ с несколькими сотнями строк в ТЧ или вы в реквизитах храните мегабайты с архивом договора)
- Сама проверка плоха (если у вас есть выгрузки между базами и вместо договора битая ссылка, то вы этот документ не откроете никогда)
Решение:
- Используем запросную модель;
- Можно поставить получение данных в привилегированном режиме.
9. Добавляем поля из таблицы в динамический список
Динамические списки – это, пожалуй, одна из самых проблемных вещей в 1С, особенно в высоконагруженных базах. Рассмотрим несколько актуальных примеров.
Постановка задания:
- В динамическом списке документа «Задание на перевозку», заказчик попросил вывести получателя из табличной части распоряжения (аргумент: 90% с одним или одинаковым получателем)
Проблема:
- Снижаем производительность лишними соединениями;
- Это явный костыль;
- Если мы захотим вывести что-то еще из другой табличной части?
Решение:
- Добавляем новый реквизит в шапку документа, который назовем «xyz_КонтрагентДляСписка»/«Первый Получатель Отправитель»
- При записи документа выбираем для заполнения первого получателя из табличной части если есть.
10. Вывод полей через точку от составного типа в динамических списках, отчетах, АРМ
Постановка задачи:
- Нам требуется в списке для ссылочных (обычно составных) полей «Регистратор», «Документ Расчетов», «Объект Расчетов» и т.п. вывести дополнительные информационные поля: «Дата», «Номер» и т.д.
В этом пожелании нет ничего необычного, т.к. всегда пользователи смотрят информацию в разрезе клиента, организации, договора или ищут нужный документ по номеру. К тому же, в каждом динамическом списке пользователь может через настройки вытащить часть интересующих его полей на форму.
Проблема:
- Это очень сплошная «боль» для пользователей при использовании РЛС.
- Доступ к данным сразу потребует наличия доступа ко всем документам регистраторов.
- Производится неявное лишнее соединение ко всем таблицам документов при РЛС.
- Страдает быстродействие.
Решение:
- Используем дополнительный регистр (будут храниться все часто используемые реквизиты документов, который заполняем при записи документа или справочника). В типовых конфигурациях есть регистр сведений «Реестр Документов».
В следующей статье мы посмотрим, как меняется план запроса в зависимости от условий.
Мероприятия:
- При проектировании учитываем возможные потребности пользователей
- Проводим архитект-ревью или мозговой штурм
- Используем базу знаний хороших решений.
11. Очень сложный запрос в динамических списках
Постановка задачи:
- Заказчик попросил в список заказов добавить информацию по выполнению заявок.
Есть динамический список документов «заказы клиентов», а также есть регистр остатков выполнения некоторого вспомогательного процесса выполнения заявок в разрезе заказов клиента. И требуется увидеть статус выполнения этих заявок в рамках основного списка.
Реализация:
В динамический список добавили соединение документов заказов клиентов с вложенным запросом на основании регистра.
Проблема:
- Данное решение довольно медленно отрабатывает из-за сложной структуры – неоправданно много данных просчитывается на SQL сервере для того чтобы отобразить 25 первых строчек.
- Время ожидания у пользователей под ограничениями находится в приделах 100-200 сек
- Поиск по подобно увеличивает время до 400-500 сек
- Особенно это заметно, когда в базе довольно много документов и движений.
Если вы застали раннюю версию УТ11 (до выхода ERP), то могли видеть подобную проблему для динамического списка подбора номенклатуры по товарам. Это решение очень сильно тормозило даже на маленькой нагрузке, и бизнес испытал "легкий" шок при попытке поработать на этой пилотной конфигурации. К счастью, в скором времени они исправились и переделали на более оптимальный вариант.
Решение:
- Создаем новый регистр сведений с измерением «Заказ клиента» и состоянием вспомогательного процесса выполнения заявок.
- Переписываем запрос на соединение двух списка документов «Заказы клиентов» с новым регистром сведений «Выполнение заявок»
- В результате время отклика ушло в нормальные значения, а поиск по подобно снизился до 10-20 сек.
Мероприятия:
- Повышаем квалификацию разработчиков:
- Посещаем конференции,
- Обсуждаем варианты реализации,
- Смотрим планируем на будущее (в базе будет много документов, а не 20-30 как на демонстрационном стенде)
12. Использование временных таблиц в динамических списках
Постановка задачи:
- Заказчик попросил внести изменения в форму выбора сделок. Требовалось добавить некоторый фильтр на сделки по партнеру, если в параметрах открытия передается ссылка на партнера.
Решение:
- В динамический список была добавлена временная таблица, которая формировала список сделок по партнеру при наличии отбора. (одно радует, что стиль "рваный запрос" не применялся)
Проблема:
- Проблема быстродействия. Если с обычным списком форма открывалась в самом худшем случае до 10 секунд, то теперь могла зависать на 60-200 секунд
- Лучше не использовать временные таблицы в динамических списках - это вам не отчеты
- Не учтены рекомендации не использовать в условиях и соединениях конструкции "Выбор", что в свою очередь просаживало быстродействие при наложении РЛС с использованием шаблона "ПоНаборамЗначений", не очень хорошо в условиях использовать отрицание условия - "НЕ РАВНО" когда нет отбора по основному индексу (все условия наиболее эффективно работают при условии "РАВНО").
Решение:
- Было решено исключить использование временной таблицы
- Исключить использование конструкции "Выбор"
- Получать список партнеров в привилегированном режиме и добавление их в запрос с помощью команды "ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка"
Мероприятия:
- Код-ревью
- Повышаем знания по основным механизмам БСП
13. Использование типа «Любая ссылка»
Что происходит:
- Хотим заложить заранее возможность использования любого документа, справочника (проектирование звездолетов)
- В задачах и бизнес-процессах – это предмет.
Проблема:
- Предприятие 1С для проверки RLS доступа по составному типу добавляет в проверку условия по всем входящим объектам.
- Получаем «дикие» тормоза в списках. На практике наблюдал по замерам время отработки прорисовки списков задач и бизнес процессов с длительностью 30 и более минут.
Решение:
- Не используем тип «Любая ссылка»;
- Выбираем типы, которые действительно используем;
- В списках выведем заранее поля использующие данные из агрегирующего регистра по подобию «Реестр документов».
14. Создаем лишние роли
Что происходит:
- Заказчик разработать новую подсистему «Производственно-технологическая подсистема»;
- Нужны новые справочники, документы, регистры.
Реализация:
- Добавили роли под каждый объект, на чтение и изменение: «Чтение справочника рабочие центры», «Добавление и изменение справочника рабочие центры», «Чтение справочника рабочие участки» и т.д.
Проблема:
- Лишние роли увеличивают сложность настройки прав;
- Больше ролей применяется к пользователю и тем самым усложняются проверки при использовании RLS.
Решение:
- Создавать кумулятивные роли: «Добавление и изменение НСИ», «Чтение технологических данных», «Чтение производственных данных» и т.д.
15. Выбор из множества с плохой уникальностью
Что происходит:
- Подбор серии при вводе по строке. Производится поиск существующих серий по данным регистра «Движение серий».
Проблема:
- Сложный запрос на каждый ввод символа,
- Используется «ПОДОБНО»,
- Часто вводят 0 или 1 – это каждая вторая серия при их количестве более 100 тысяч – бессмысленная подсказка.
- Используем разрешенные и добавляем ограничение RLS там где не нужно (похоже на своеобразный, но не удачный фильтр) - это дополнительно увеличивает время обработки (иногда 60 и более секунд)
Решение:
- Ограничить подсказку длиной 3 и более символов.
- Добавить фильтры по периоду.
- Проиндексировать в регистре измерение «Серия» и/или установить его первым по порядку.
- Использовать другие алгоритмы (регистр «живых» серий на складе)
- Добавить привилегированный режим получения данных (сотрудник склада должен видеть все серии, что доступны ему)
16. При записи или проведении выполняем сложные расчеты
Постановка задачи на разработку:
- Заказчик попросил пересчитывать процент оплаты заказа клиента при расчетах по заказам.
- Или рассчитать себестоимость - ФИФО по партиям.
Реализация:
- Мы вставляем в процедуру проведения алгоритм для пересчета статусов по регистру сведений статусы расчетов.
Проблема:
- Это длительная процедура (используется ФИФО, большой объема документов)
- Блокировки (пользователи работают по тем же метаданным и аналитикам)
- Кто-то запустил пере проведение набора документов - система уходит в offline
Решение:
- Данный функционал выносится в отдельное фоновое задание.
- Данные для обновления расчетов при записи объектов добавляются в регистр сведений «К Расчету Процента Оплаты» или «К расчету себестоимости»
- Отдельный регистр с расширенной аналитикой
17. Создаем узкое горлышко
Что происходит:
- Переходим с одной версии на другую;
- Переходим на новый механизм «Видов запасов», т.е. появляются устаревшие виды. Много позиций ходового товара попало в устаревшие виды запасов, т.е. много менеджеров "одномоментно" продают товар из разных подразделений.
Реализация:
- Добавили новый регистр сведений «Устаревшие виды запасов с остатками» с одним измерением «Вид запасов»;
- Добавили блокировку на этот регистр при списании товаров организаций;
Проблема:
- Устаревшие виды запасов используются по множеству складов и организаций;
- При активных продажах ходового устаревшего «вида» ловим блокировки;
- Система «умирает» при пике пользователей (более 300-500 online) в некоторые моменты времени.
Решение:
- Так делать нельзя!
- Требуется переосмысление реализации подсистемы – добавление большего числа аналитик в измерения (Склад, Организация, ВидНоменклатуры, Номенклатура и т.п.), отложенная процедура списания устаревших товаров с остатками, другие мероприятия.
18. Используем com соединение
Что происходит:
- Для получения данных из внешней базы – кросс отчеты, сравнения документов и т.п.
- Перенос данных.
Проблема:
- Долгая процедура инициализации (подгружает всю конфигурацию)
- Соответствие версий предприятия 1С для баз данных
- Доступно только для Windows.
Решение:
- Используем конвертацию, выгрузку/загрузку из файлов.
- Используем REST сервисы
II) Мероприятия по повышению качества продукта
1. Знание основ (БСП, правила разработки и др.)
Мы повышаем общий уровень разработчиков и команды в целом. В результате у нас будет:
- Использовать готовые решения, а не изобретать велосипеды
- Качество кода
- Рефакторинг или уменьшение технического долга
- Правильность решений, снижение количества ошибок и общая эффективность команды
Хотя сама конфигурация БСП и содержит кое где перлы, но практически все существующие решения уже имеют ее интеграцию. Поэтому знание основных механизмов и использование ее функционала значительно повышают скорость и качество разработки.
Проведение процедуры код-ревью
2. Кейсы, база знаний
Знания и приемы, которые команда получает в процессе работы:
- Можно создать вики ресурс
- Использовать Confluence от JIRA
- Excel в общей папке или еще что-то
3. Код-ревью
"Это систематическая проверка исходного кода программы с целью обнаружения и исправления ошибок, которые остались незамеченными в начальной фазе разработки. Целью обзора является улучшение качества программного продукта и совершенствование навыков разработчика." - из Вики.
Иными словами - это проверка качества кода, прежде чем поместить ветку в мастер:
- Интернет - ищем код-ревью, обзор кода или code-review
- Как завести у себя в команде код-ревью. Отвечаем на вопросы
- По следам код-ревью
4. Архитект-ревью
Это обсуждение, согласование архитектуры решения прежде чем начать разработку:
- Позволит избежать провалов в архитектуре
- Обсуждение и выбор оптимального решение
- Методика разработки «сверху вниз»
5. Тестирование
Это мощный, чудесный механизм, позволяющий выявить различные проблемы на различных этапах разработки:
- Юнит-тесты
- Сценарные тесты
- Нагрузочное тестирование
- Интеграционное тестирование
III) Инструменты
1. Конфигурации проверки качества кода «АПК»
Позволяет вам довольно успешно проверять код на наличие требованием стандартов (1С:Совместимо). В комплексе с данным инструментом можно развернуть и Sonar Cube с плагином для 1С проверки на «запах кода».
2. Конфигурация «Мониторинг производительности»
Позволяет автоматизировать и упростить часть задач решаемых задач по поиску проблемных мест в ваших рабочих базах и базах разработчиков.
Список долгих запросов:
- Механизм настраивается за 15 минут (5 простых шагов и 15 минут на разворачивание инструмента мониторинга проблем производительности базы 1С).
- Позволяет выполнять действительно быстрый анализ и поиск проблемных точек в рабочей базе.
- Примите за практику открывать утром и анализировать проблемные ситуации за предыдущий день в два клика!
Тексты ошибок:
- Уже настроен, если вы выполнили пункт выше)
- Показывает проблемные точки в работе программы
- Есть интеллектуальная классификация существующих ошибок
Метрики состояния в готовом виде:
- Позволяет анализировать наличие проблем производительности в реальном режиме времени
- Есть возможность выполнять оперативные воздействия по результатам анализа
- Интеллектуальное детектирование проблем и информирование через различные мессенджеры
3. SQL Профайлер (Microsoft SQL Profiler) или Microsoft SQL Management Studio Extended Events
Инструмент, позволяющий в реальном времени анализировать запросы, которые приходят из 1С. И думать над задачей оптимизации. В следующей статье мы рассмотрим пример работы с ним для части рассмотренных выше случаев, будет интересно, по крайней мере у нас в команде было очень интересно обсудить эту тему. Также рассмотрим в связке с уже бесплатным инструментом "SQL Sentry Plan Explorer".
4. Блокнот и RegExpr
Это, на мой взгляд, очень сложные мероприятие, когда под рукой есть готовые инструменты. Если вы только не являетесь специалистом 80-го уровня и на завтрак едите планы запросов.
Видео выступления
Заключение
- Учитесь и развивайтесь
- Используйте автоматизацию
- Используйте правильные подходы
- Используйте мировые практики
- Участвуйте в open source проектах
Ссылки на источники информации
Все ссылки и дополнительные соберем в одном месте.
- Фреймворк «Мониторинг производительности»
- Фреймворк «Тестирование 3.0»
- Как завести у себя в команде код-ревью. Отвечаем на вопросы
- По следам код-ревью
- Анализ проблем производительности по динамике мониторинга RAS 1C
- 5 простых шагов и 15 минут на разворачивание инструмента мониторинга проблем производительности базы 1С
- Как работает серверный вызов в 1С
- 1C ITS