Диагностика медленных запросов в 1С 8.3
Содержание
Проверка запросов в 1С 8.3 идёт по цепочке: замером производительности и технологическим журналом находят медленный вызов, его текст и план разбирают в консоли запросов и на стороне SQL Server, после — ищут блокировки и правят индексы. На эти четыре шага сводится почти любая диагностика производительности.
Браться за оптимизацию вслепую бессмысленно. Сначала нужны цифры: какой запрос выполняется дольше всех, сколько раз в минуту он вызывается и чего он ждёт — процессор, диск или снятия блокировки. Ниже — инструменты, которые эти цифры дают, и типовые приёмы, которыми потом правят код.
Консоль запросов: смотрим текст, результат и время
Консоль запросов — типовая внешняя обработка (входит в комплект ИТС и в набор «Инструменты разработчика»). Она открывает текст запроса, выполняет его на боевых данных и показывает результат с временем выполнения. Это первый инструмент, когда запрос уже известен и нужно понять, что он возвращает и как долго.
Чтобы открыть обработку в режиме «1С:Предприятие»: Главное меню → Файл → Открыть, выберите файл .epf. Потребуется право на открытие внешних обработок.
В консоли удобно:
- 📝 вставить текст запроса и выполнить его, не трогая конфигурацию;
- ⏱ увидеть длительность выполнения прямо под кнопкой «Выполнить»;
- 🔧 собрать запрос через встроенный конструктор, если текста ещё нет;
- 🧩 подставить параметры и прогнать запрос с теми же значениями, что и в проблемной операции.
Для запросов внутри конфигурации есть и штатный путь: в конфигураторе откройте модуль, установите курсор в строку запроса и вызовите Конструктор запроса из контекстного меню. Он же показывает, какие таблицы и соединения реально участвуют.
Консоль показывает, что запрос делает и сколько это длится. Почему он медленный на стороне СУБД — видно уже в технологическом журнале и в плане SQL.
Замер производительности: находим самый долгий вызов
Когда непонятно, какой именно запрос тормозит проведение или открытие формы, запускают замер производительности. Делается это из конфигуратора: меню Отладка → Замер производительности. После старта выполните проблемное действие в пользовательском режиме и остановите замер.
Результат — список строк кода с суммарным временем и числом вызовов. Сортировка по времени сразу выводит наверх «горячие» участки: как правило, это запрос в цикле или тяжёлое соединение.
Параллельно смотрят на APDEX — интегральную оценку отклика ключевых операций. Если он просел по конкретной операции, замер производительности покажет, в какой именно строке кода уходит время.
Технологический журнал: ловим долгие запросы к СУБД
Технологический журнал (ТЖ) пишет события платформы на диск, в том числе каждый запрос к СУБД. Это основной способ поймать медленные запросы на работающей базе, не подсаживаясь отладчиком к каждому сеансу.
Журнал настраивается файлом logcfg.xml в каталоге conf платформы (путь вида C:\Program Files\1cv8\conf). Вот конфигурация, которая пишет только запросы к СУБД длительностью примерно от трёх секунд:
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\logs\tj" history="24">
<event>
<eq property="name" value="DBMSSQL"/>
<ge property="duration" value="3000000"/>
</event>
<property name="all"/>
</log>
</config>
Здесь важны два свойства:
name="DBMSSQL"— события запросов к серверу СУБД (текст вSql). СобытиеSDBL— тот же запрос на языке запросов 1С, его удобно сопоставлять с кодом.duration— порог длительности в микросекундах (3000000≈ 3 секунды). Порог подбирают так, чтобы в лог попадали именно проблемные запросы, а не весь поток.
После записи журнала файлы из каталога location разбирают: ищут самые долгие события DBMSSQL, по planSQLText смотрят план выполнения, по Context — из какого места конфигурации пришёл запрос.
Включённый технологический журнал пишет на диск непрерывно и сам по себе нагружает систему. Ставьте узкий фильтр, короткое окно (history в часах) и не забывайте удалять logcfg.xml после диагностики — иначе лог быстро забьёт диск.
Поиск и разбор блокировок
Если операция «висит», но процессор и диск свободны — почти наверняка дело в блокировках. Сеанс ждёт, пока другой сеанс освободит данные. В управляемом режиме блокировок это ловят тем же технологическим журналом по трём событиям:
TLOCK— установка и снятие управляемых блокировок;TTIMEOUT— сеанс не дождался блокировки за отведённое время (та самая ошибка «Превышено время ожидания предоставления блокировки»);TDEADLOCK— взаимоблокировка: два сеанса ждут данные друг друга.
По паре TTIMEOUT/TDEADLOCK видно, какой ресурс не поделили и какие сеансы в этом участвовали. Дальше смотрят, можно ли сократить длительность транзакции: вынести запросы из транзакции, уменьшить объём читаемых данных, упорядочить запись документов в едином порядке.
На стороне SQL Server текущие блокировки видно через системные представления:
SELECT
r.session_id AS сеанс,
r.blocking_session_id AS кто_блокирует,
r.wait_type,
r.wait_time,
t.text
FROM sys.dm_exec_requests AS r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE r.blocking_session_id <> 0;
Непустой blocking_session_id — это и есть цепочка ожидания. Для разового взгляда хватает процедуры sp_who2: в колонке BlkBy стоит номер блокирующего сеанса.
Чтобы ловить длительные блокировки автоматически, включают отчёт о заблокированных процессах: задают порог blocked process threshold через sp_configure и собирают событие Blocked process report расширенными событиями. В отчёте виден XML с обоими сеансами — тем, что ждёт, и тем, что держит ресурс, — вместе с текстами их запросов. Это снимает нужду сидеть у sp_who2 и ждать, пока блокировка повторится.
Для системного анализа блокировок в кластере используют Центр управления производительностью (ЦУП) из корпоративного инструментального пакета — он собирает события ТЖ и строит картину взаимных ожиданий без ручного разбора логов.
Что показывает SQL Server: профайлер и системные представления
Когда база работает в клиент-серверном варианте на MS SQL Server, тяжёлые запросы удобно разбирать средствами самой СУБД.
SQL Server Profiler перехватывает запросы в реальном времени: создаёте трассировку по событию RPC:Completed / SQL:BatchCompleted, фильтруете по Duration и видите текст, время и число чтений. Инструмент наглядный, но устаревший.
Расширенные события (Extended Events) — современная замена профайлера. Нагрузка на сервер заметно меньше, поэтому для боевой базы берут именно их: сессия xEvents по тем же событиям завершения запросов пишет данные в файл, который потом разбирают.
Системные представления (DMV) дают сводку без трассировки. Топ самых затратных запросов — по накопленной статистике:
SELECT TOP 20
qs.total_worker_time / qs.execution_count AS среднее_cpu,
qs.execution_count AS вызовов,
SUBSTRING(t.text, qs.statement_start_offset / 2, 200) AS запрос
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS t
ORDER BY qs.total_worker_time DESC;
Ещё полезно посмотреть sys.dm_os_wait_stats — чего сервер ждёт чаще всего. Длинные ожидания типа PAGEIOLATCH указывают на дисковую подсистему, LCK_* — снова на блокировки.
Трассировка профайлером на нагруженной боевой базе сама добавляет нагрузку. Запускайте её на короткое окно и с жёстким фильтром по длительности, а для постоянного мониторинга выбирайте расширенные события.
Индексы и статистика: перестроение и обслуживание
Медленный запрос на стороне SQL часто упирается не в текст, а в индексы. Сервер либо сканирует таблицу целиком вместо поиска по индексу, либо строит план по устаревшей статистике.
Сначала оценивают фрагментацию:
SELECT OBJECT_NAME(ips.object_id) AS таблица,
i.name AS индекс,
ips.avg_fragmentation_in_percent AS фрагментация
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') AS ips
JOIN sys.indexes AS i
ON i.object_id = ips.object_id AND i.index_id = ips.index_id
WHERE ips.avg_fragmentation_in_percent > 10
ORDER BY ips.avg_fragmentation_in_percent DESC;
Дальше действуют по уровню фрагментации:
| Фрагментация | Действие | Команда |
|---|---|---|
| 10–30 % | Реорганизация (лёгкая) | ALTER INDEX ... REORGANIZE |
| больше 30 % | Перестроение | ALTER INDEX ... REBUILD |
| — | Обновить статистику | UPDATE STATISTICS |
ALTER INDEX ALL ON _InfoRg12345 REBUILD; -- фрагментация выше 30 %
ALTER INDEX ALL ON _InfoRg12345 REORGANIZE; -- фрагментация 10–30 %
Перестроение индекса командой REBUILD без опции ONLINE блокирует таблицу на время операции. Опция ONLINE доступна только в редакции Enterprise. Запускайте перестроение в окно низкой активности, иначе пользователи упрутся в заблокированные таблицы.
Бывает, что индексы в порядке, а один и тот же запрос ведёт себя по-разному от запуска к запуску. Частая причина — план, построенный под нетипичное значение параметра и закэшированный для всех остальных. В такой ситуации помогает обновление статистики и повторная компиляция запроса; хронические случаи разбирают уже прицельно, с планом из профайлера.
Разовыми командами обслуживание не ограничивают — его ставят на регламент: план обслуживания SQL Server или готовый набор скриптов, который сам выбирает между реорганизацией и перестроением по проценту фрагментации и обновляет статистику.
В файловом варианте индексов SQL нет. Там обслуживание выполняют из конфигуратора: Администрирование → Тестирование и исправление информационной базы с включённой реиндексацией таблиц. Операция монопольная — все сеансы нужно закрыть.
Ошибки в тексте запроса, которые тормозят базу
Половину проблем создаёт не СУБД, а сам текст запроса на языке 1С. Самые частые:
- Запрос в цикле. Классика: по каждой строке табличной части выполняется отдельный запрос. Решение — вынести всё в один запрос и обработать результат выборкой или соединением с таблицей значений.
- Отбор у виртуальной таблицы через
ГДЕ. У таблиц остатков и оборотов параметры отбора задают в скобках самой виртуальной таблицы, а не во внешнемГДЕ. Иначе платформа сначала считает итоги по всему регистру, а уже потом отфильтрует — на больших регистрах это дорого. - Обращение к реквизитам через точку у составного типа. Поле вида
Ссылка.Владелец.Наименование, гдеВладелецсоставного типа, превращается в левые соединения со всеми таблицами этого типа. Уточняйте тип функциейВЫРАЗИТЬ(... КАК ...). - Соединения с подзапросами. Соединять лучше с временными таблицами, а не с подзапросами: по временной таблице можно построить индекс через
ИНДЕКСИРОВАТЬ ПО. - Фильтр, который не ложится на индекс. Условия с
НЕ, сПОДОБНОи шаблоном"%текст"в начале строки, а также отбор по неиндексированному полю заставляют сервер сканировать таблицу целиком. - Лишние поля и
ВЫБРАТЬ *. Чем меньше полей и строк тянет запрос, тем меньше работы у СУБД и тем выше шанс, что хватит покрывающего индекса.
Проверять эти места удобно связкой: текст запроса — из SDBL технологического журнала, реальный план — из planSQLText или из профайлера. Если план показывает Scan вместо Seek по большой таблице — почти наверняка виновато одно из условий выше.
Частые вопросы
Можно ли посмотреть текст SQL-запроса, не настраивая технологический журнал?
sys.dm_exec_requests с sys.dm_exec_sql_text, а историю самых затратных хранит sys.dm_exec_query_stats. Технологический журнал нужен, когда важен контекст конфигурации — из какого модуля пришёл запрос.Чем «Замер производительности» отличается от технологического журнала?
Как понять, что тормозят именно блокировки, а не медленный запрос?
TTIMEOUT или TDEADLOCK, а на SQL Server у сеанса непустой blocking_session_id.