Каждый администратор и разработчик 1С рано или поздно сталкивается с загадочными проблемами производительности, которые проявляются крайне избирательно. Представьте ситуацию: база данных «1С:Управление производственным предприятием» (УПП), пользователь открывает карточку контрагента, переходит на вкладку «События», и система «зависает» на 10, 20 или даже 30 секунд. При этом у соседнего коллеги с точно такими же правами доступа и на том же терминальном сервере эта вкладка открывается мгновенно.
В этой статье мы подробно разберем, почему стандартный замер производительности в конфигураторе может показывать ложные результаты, как правильно настроить технологический журнал для поиска «тихих» зависаний и почему радикальное переписывание форм — это худший путь решения проблемы, которую можно устранить за два клика.
Первое, что делает разработчик при возникновении лагов — запускает Замер производительности в конфигураторе. Однако в нашем случае замер может показать ошеломляюще быструю работу — например, 0,000129с на самую долгую операцию. Выясним причину, почему так происходит. Выделим два главных фактора:
-debug, все вызовы и операции, выполняемые на стороне сервера, просто не попадут в замер производительности на клиенте. Клиентская часть отрабатывает моментально, а вся задержка происходит на стороне СУБД или сервера приложений.Для того чтобы увидеть реальную картину происходящего, нам необходимо переключить конфигурацию на локальную файловую копию или включить отладку на сервере, а также задействовать мощный инструмент диагностики — Технологический журнал (ТЖ).
Рассмотрим, как локализовать проблему с помощью ТЖ. Если у нас есть возможность развернуть файловую копию базы данных, где воспроизводится баг под конкретным пользователем, мы можем настроить сбор логов локально. Это позволит избежать лишней нагрузки на рабочий сервер.
Разберем по шагам процесс настройки ТЖ для файловой базы данных:
Шаг 1. В каталоге шаблонов настроек (обычно это C:\Program Files\1cv8\conf или индивидуальная папка пользователя) создадим текстовый файл с именем logcfg.xml.
Шаг 2. Запишем в него конфигурацию для отслеживания событий работы с файловой СУБД (событие DBV8DBEng). Если бы мы исследовали клиент-серверный вариант на MS SQL, мы бы отслеживали событие dbmssql. Нам также необходимо собирать подробные свойства запросов, поэтому укажем вывод всех свойств.
Посмотрим на пример файла конфигурации ТЖ:
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\log\log1c" history="1">
<event>
<eq property="Name" value="DBV8DBEng"/>
</event>
<property name="all"/>
</log>
</config>
Шаг 3. Запустим 1С под проблемным пользователем, перейдем на вкладку «События», дождемся окончания зависания и закроем программу. В каталоге C:\log\log1c сформируется лог-файл.
Проанализируем полученные данные. В логах мы увидим примерно следующую картину:
56:50.314001-38732001,DBV8DBEng,...,Sdbl='SELECT ALLOWED TOP 20 R.Date_Time A1, ...'
Число 38732001 после дефиса показывает длительность выполнения операции в микросекундах. Это означает, что запрос выполнялся целых 38,7 секунды! При этом у другого пользователя аналогичный запрос на получение тех же самых данных занимает всего 2828000 микросекунд (около 2,8 секунды). Физический запрос в базу данных один и тот же, но время выполнения различается более чем в 13 раз.
Почему один и тот же динамический список работает быстро для одного пользователя и критически медленно для другого? Секрет кроется в индивидуальных настройках формы и списка, которые хранятся непосредственно в системных таблицах базы данных 1С.
Рассмотрим подробнее механизмы СУБД, которые приводят к деградации производительности:
1. Сортировка по неиндексированному полю. По умолчанию динамический список выбирает записи, используя индекс по умолчанию (например, по дате документа). СУБД легко считывает первые 20 записей по индексу. Но если проблемный пользователь случайно или намеренно кликнул по шапке колонки, которая не имеет индекса в СУБД (например, текстовый реквизит «Суть события» или реквизит, получаемый через точку от другого объекта — Ответственный.Подразделение), СУБД больше не может читать данные порциями. Чтобы показать первые 20 строк с такой сортировкой, SQL-сервер выполняет полный перебор (Full Table Scan) всей многомиллионной таблицы событий, сортирует их во временной памяти (TempDB) и только потом отдает результат. Это вызывает колоссальный лаг.
2. Пользовательские отборы и группировки. Если пользователь настроил сложную группировку данных (например, по контрагентам или видам событий), платформе приходится вычислять структуру дерева группировок, что требует сканирования всей таблицы документов, сводя на нет преимущества динамического считывания порций.
3. Условное оформление формы. Сложные правила раскраски строк (условное оформление), завязанные на реквизиты связанных таблиц, заставляют платформу генерировать тяжелые левые соединения (LEFT JOIN) при выводе каждой строки списка, что перегружает процессор сервера СУБД.
Если вы столкнулись с подобной ситуацией, не спешите переписывать конфигурацию, отказываться от динамических списков или удалять элементы базы данных. Существует несколько простых и эффективных способов вернуть быстродействие системы без изменения кода конфигурации.
Это самый быстрый и безболезненный способ, не требующий прав администратора:
После этого все пользовательские сортировки, отборы и условное оформление будут удалены, а список вернется к первоначальному, оптимизированному разработчиками виду.
Если форма зависает «намертво» и зайти в меню настроек списка под учетной записью пользователя невозможно, администратор может сбросить настройки удаленно:
В случаях, когда стандартные административные формы очистки недоступны или дают сбой, мы можем воспользоваться программным кодом. Напишем простую внешнюю обработку, которая удалит сохраненные настройки формы динамического списка для конкретного пользователя с использованием встроенного языка 1С:
Процедура ОчиститьНастройкиПользователя()
ИмяПользователя = "ИвановИИ"; // Укажите имя проблемного пользователя
КлючОбъекта = "Справочник.Контрагенты.Форма.ФормаЭлемента.СписокСобытий"; // Пример ключа настроек
// Удаляем настройки из системного хранилища настроек динамических списков
ХранилищеСистемныхНастроек.Удалить(КлючОбъекта, "", ИмяПользователя);
Сообщить("Настройки динамического списка для пользователя " + ИмяПользователя + " успешно сброшены!");
КонецПроцедуры
Рассмотрим подробнее, как разработчик может предотвратить подобные проблемы на уровне проектирования системы:
Индексировать (или Индексировать с дополнительным упорядочиванием). Это создаст индекс в СУБД, и сортировка по этому полю перестанет замедлять систему.Основная таблица обязательно должен быть указан конкретный объект метаданных (например, Документ.Событие). Если это поле оставить пустым (даже при наличии простого текста запроса), платформа лишится возможности оптимизировать выборку порциями и будет всегда выполнять неоптимальные запросы.Таким образом, своевременная диагностика с помощью технологического журнала и понимание внутренних механизмов СУБД позволяют решать сложнейшие проблемы производительности за считанные минуты без дорогостоящего и избыточного переписывания кода конфигурации.