Снимаем и читаем план выполнения запроса в 1С

· 10 мин

Содержание

План выполнения строит не 1С, а СУБД — MS SQL Server или PostgreSQL. 1С переводит запрос с внутреннего языка в SQL, отдаёт его серверу баз данных, и уже оптимизатор СУБД решает, как физически доставать данные. Поэтому задача «получить план запроса 1С» распадается на два шага: снять текст SQL, который реально ушёл на сервер, и получить для него план выполнения.

Снять план можно двумя путями. Первый — технологический журнал платформы: события DBMSSQL (MS SQL) и DBPOSTGRS (PostgreSQL) пишут текст SQL, а тег <plansql/> добавляет к ним сам план. Второй — средства СУБД: в PostgreSQL это команда EXPLAIN, в MS SQL — кнопка показа плана в SQL Server Management Studio. Разберём оба способа, научимся читать операторы и поймём, почему один и тот же запрос то летает, то висит минуту.

Где рождается план и что такое «запрос 1С» для сервера

В файловом варианте базу обслуживает встроенная СУБД, план от неё получить штатно нельзя. Всё, что ниже, относится к клиент-серверному варианту на MS SQL или PostgreSQL.

Запрос, который вы пишете на встроенном языке, проходит несколько превращений:

  • 🔹 язык запросов 1С → внутреннее представление SDBL;
  • 🔹 SDBL → текст SQL под конкретную СУБД;
  • 🔹 SQL → план выполнения, который строит оптимизатор сервера.

Имена таблиц и полей в этом SQL — не Номенклатура и Контрагенты, а служебные _Reference123, _Document456 с полями вида _Fld789. Поэтому прочитать план «в лоб» мало — нужно сопоставить служебные имена с объектами конфигурации. Это делают по структуре хранения (в конфигураторе есть служебная таблица соответствия) либо автоматически — в специализированных инструментах анализа.

Если нужна только скорость кода, а не план, начните с замера производительности в конфигураторе (Отладка → Замер производительности). Он покажет, какая строка встроенного языка тратит время. Но SQL-план он не даёт — для него идём в технологический журнал или СУБД.

Способы снять план выполнения

Выбор инструмента зависит от того, есть ли у вас доступ к серверу СУБД и нужен ли план «боевого» запроса под реальной нагрузкой.

Технологический журнал платформы

Самый универсальный путь: план снимается там же, где работает проблемный запрос, под реальными данными. Настраивается файлом logcfg.xml в каталоге conf платформы.

Минимальная конфигурация для сбора планов тяжёлых запросов:

<config xmlns="http://v8.1c.ru/v8/tech-log">
  <log location="C:\v8log" history="24">
    <event>
      <eq property="name" value="DBPOSTGRS"/>
      <ge property="duration" value="1000000"/>
    </event>
    <property name="all"/>
    <plansql/>
  </log>
</config>

Разбор по строкам:

  1. location — каталог для логов, history — сколько часов хранить.
  2. Фильтр по событию: DBPOSTGRS для PostgreSQL, DBMSSQL для MS SQL.
  3. duration в микросекундах: 1000000 — ловим только запросы дольше 1 секунды, чтобы не писать всё подряд.
  4. <plansql/> — главный тег: именно он добавляет к событию свойство planSQLText с планом выполнения.

Технологический журнал без фильтра по duration на рабочей базе за минуты забьёт диск десятками гигабайт. Всегда ставьте порог длительности и короткий history, а после сбора данных журнал отключайте. Сам сбор планов добавляет нагрузку на сервер.

В логе каждое событие DBPOSTGRS/DBMSSQL покажет свойства Sql (текст запроса) и planSQLText (план). Платформа при этом подставляет в план реальные значения параметров — это ценно, потому что от параметра зависит выбор оптимизатора.

Средства СУБД напрямую

Когда SQL уже на руках (из журнала или из консоли запросов с показом SQL), план удобно снимать на самом сервере.

PostgreSQL — команда EXPLAIN:

-- только оценочный план, запрос не выполняется
EXPLAIN SELECT ...;

-- фактический план: запрос РЕАЛЬНО выполняется, с таймингом по операторам
EXPLAIN (ANALYZE, BUFFERS) SELECT ...;

EXPLAIN (ANALYZE ...) действительно выполняет запрос. Для SELECT это безопасно, а вот INSERT/UPDATE/DELETE изменят данные. Оборачивайте такие проверки в транзакцию с откатом: BEGIN; EXPLAIN (ANALYZE) ...; ROLLBACK;.

MS SQL — SQL Server Management Studio:

  • Ctrl+L — показать оценочный план, без выполнения запроса;
  • Ctrl+M — включить сбор фактического плана, план появится после выполнения;
  • либо профилировщик/расширенные события с планом Showplan XML.

Специализированные инструменты

  • ЦУП (Центр управления производительностью) из КИП — собирает планы автоматически и сразу привязывает их к контексту 1С: видно, какой документ и какая строка кода породили запрос. Удобно для разбора проблем на бою.
  • Онлайн-визуализаторы планов PostgreSQL (например, explain.tensor.ru) — вставляете текстовый вывод EXPLAIN (ANALYZE) и получаете наглядное дерево с подсветкой узких мест. Данные при этом уходят на сторонний сервис — учитывайте для чувствительных баз.
Какой инструмент выбрать под вашу задачу?

Логический и физический план: в чём разница

Это разные уровни одного процесса, и путать их — частая причина неверных выводов.

Логический план — что нужно сделать: какие таблицы соединить, по какому условию, что отфильтровать и сгруппировать. Он не зависит от того, как данные лежат на диске, и прямо следует из текста запроса.

Физический план — как именно сервер это выполнит: каким алгоритмом соединит таблицы, каким способом прочитает каждую. Его выбирает оптимизатор, опираясь на статистику, индексы и оценку стоимости вариантов.

Пример: логически «соединить заказы с контрагентами» — одно действие. Физически оптимизатор выберет между:

  • Nested Loops — для каждой строки одной таблицы ищет совпадения во второй по индексу; хорош, когда строк мало;
  • Hash Join / Hash Match — строит хеш-таблицу; хорош на больших объёмах;
  • Merge Join — сливает два отсортированных потока.

Команды EXPLAIN и план в SSMS показывают именно физический план — то, что реально будет исполнено. Оценочный план (Ctrl+L, EXPLAIN без ANALYZE) — это предсказание оптимизатора. Фактический (Ctrl+M, EXPLAIN ANALYZE) — что произошло на самом деле. Главный диагностический сигнал — расхождение между оценочным и фактическим числом строк. Если оптимизатор ждал 10 строк, а пришло 2 000 000, он выбрал неподходящий алгоритм, и запрос будет медленным.

Как читать операторы графического плана

План читают от листьев к корню: сначала выполняются узлы чтения таблиц, затем соединения, сортировки, агрегации. В графическом плане толщина стрелок между узлами отражает поток строк — толстая стрелка там, где её быть не должно, и есть узкое место.

Ключевые операторы и что они значат:

Оператор (MS SQL / PostgreSQL)Что делаетКогда это сигнал проблемы
Index Seek / Index ScanТочечный поиск по индексуНорма, самый дешёвый доступ
Table Scan, Clustered Index Scan / Seq ScanПолный проход таблицыПлохо на большой таблице с выборкой немногих строк
Key Lookup, RID Lookup / Bitmap Heap ScanДочитывание строк по ссылке из индексаМного таких — не хватает покрывающего индекса
Nested Loops / Nested LoopСоединение цикломПлохо, если внешних строк много
Hash Match / Hash JoinСоединение через хешНорма на объёмах; на мелких данных — перебор
Sort / SortСортировкаДорого; иногда её можно убрать индексом

На что смотреть в первую очередь:

  1. Scan по большой таблице там, где ждали точечную выборку, — обычно значит, что индекс не подходит под условие.
  2. Расхождение rows оценочных и фактических (в EXPLAIN ANALYZE — поле rows=... actual rows=...) — проблема со статистикой или с оценкой параметра.
  3. Самый дорогой узел по стоимости — отправная точка, но не приговор: стоимость в оценочном плане может врать именно из-за плохой статистики.
  4. Операторы Sort и Spill (сброс на диск) — признак нехватки памяти под операцию.

В PostgreSQL сразу смотрите последние строки вывода EXPLAIN ANALYZE: Planning Time и Execution Time. Если планирование дольше выполнения — запрос слишком сложный или много соединений.

Временные таблицы в плане запроса

Запросы 1С активно используют временные таблицы — через конструкцию ПОМЕСТИТЬ и менеджер временных таблиц. В SQL они превращаются во временные таблицы СУБД (#tt в MS SQL, временные таблицы в PostgreSQL). В плане они видны как отдельные шаги создания и чтения.

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

Что с этим делать на уровне запроса 1С:

  • Индексируйте временные таблицы по полям соединения и отбора: ПОМЕСТИТЬ ВТ ... ИНДЕКСИРОВАТЬ ПО Контрагент.
  • Не соединяйте в одном запросе много вложенных подзапросов — вынесите промежуточные наборы во временные таблицы. Оптимизатору проще работать с материализованным набором, чем с пятиэтажным подзапросом.
  • Соединения с виртуальными таблицами регистров (остатки, обороты) тоже лучше предварительно складывать во временную таблицу, если результат используется дальше несколько раз.

Слишком много временных таблиц — тоже проблема: каждая порождает запись в служебную базу tempdb (MS SQL) и свои накладные расходы. Баланс важнее крайностей.

В плане обращайте внимание, читается ли временная таблица полным проходом (это нормально, если она маленькая) и не делает ли сервер по ней Nested Loops с большой таблицей — верный признак, что не хватило индекса на временной таблице.

Как индексы и статистика меняют план

Оптимизатор выбирает физический план не наугад, а по оценке стоимости. Основа оценки — статистика: гистограмма распределения значений в столбцах. По ней сервер прикидывает, сколько строк вернёт условие, и под это число подбирает операторы.

Отсюда два главных рычага:

Статистика. Если она устарела (данные выросли, а статистика помнит старое распределение), оценки будут неверными, и план — плохим. Обновление:

  • PostgreSQL — команда ANALYZE (и фоновый autovacuum, который её запускает);
  • MS SQL — UPDATE STATISTICS и авто-обновление статистики.

Признак устаревшей статистики в плане — именно то расхождение оценочных и фактических строк, о котором шла речь выше.

Индексы. Подходящий индекс превращает Scan в Seek. Но индекс помогает, только если условие отбора соответствует порядку полей в индексе. Индекс по (Организация, Дата) ускорит отбор по организации и по организации с датой, но не поможет отбору только по дате.

Ситуация в планеВероятная причинаЧто проверить
Seq Scan / Table Scan большой таблицыНет индекса под условие или он не выбранЕсть ли индекс по полям отбора
Оценка строк далека от фактаУстаревшая статистикаЗапустить ANALYZE / UPDATE STATISTICS
Много Key LookupИндекс не покрывает нужные поляПокрывающий индекс
Разный план на разных параметрахПерекос данных, sniffing параметраСтатистика, принудительная перекомпиляция

Индексы в 1С задают на уровне конфигурации (реквизиты, измерения регистров, индексирование реквизитов), и платформа создаёт их в СУБД. Прямое создание индексов в СУБД в обход конфигурации 1С не поддерживает — такой индекс платформа может удалить при реструктуризации.

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

Ошибки при чтении плана запроса

Разобрать план правильно не менее важно, чем его снять. Пять ловушек, на которых чаще всего спотыкаются:

  1. Смотрят только оценочный план. Он показывает намерения оптимизатора, а не реальность. Проблему с объёмом данных видно лишь в фактическом плане (EXPLAIN ANALYZE, Ctrl+M).
  2. Гонятся за узлом с наибольшим процентом стоимости. Стоимость — оценка. При плохой статистике самый «дорогой» по проценту узел может быть ни при чём, а настоящий тормоз — там, где оценка занижена.
  3. Считают любой Scan злом. Полный проход маленькой таблицы (справочник на 50 строк) дешевле, чем поход через индекс. Scan плох только на большой таблице при выборке немногих строк.
  4. Снимают план на пустой или тестовой базе. На 100 записях оптимизатор выберет один план, на 10 миллионах — другой. План нужен на объёме, близком к боевому.
  5. Забывают про параметры. Один и тот же запрос с разными значениями параметра может получить разные планы из-за перекоса данных. Снимайте план с теми значениями, на которых реально тормозит.

Не делайте выводов по одному запуску EXPLAIN ANALYZE: первый прогон мог читать данные с диска, второй — уже из кеша. Сравнивайте повторные запуски.

Частые вопросы

Можно ли получить план запроса средствами самой 1С, без доступа к СУБД?
Текст SQL и план — через технологический журнал с тегом <plansql/>, доступ к серверу СУБД для этого не нужен, достаточно прав на платформе и к каталогу логов. Замер производительности и консоль запросов показывают время и SQL, но не план выполнения.
Чем отличается оценочный план от фактического?
Оценочный — прогноз оптимизатора, запрос не выполняется. Фактический — результат реального выполнения с числом строк и таймингом по операторам. Для диагностики нужен фактический: расхождение оценки и факта и есть главный симптом.
Почему в плане служебные имена вроде `_Reference123` вместо таблиц конфигурации?
Так 1С хранит объекты в СУБД. Сопоставить служебные имена с объектами конфигурации можно по структуре хранения (служебная таблица в конфигураторе) либо автоматически — в ЦУП и подобных инструментах.
Безопасно ли снимать план на рабочей базе?
EXPLAIN без ANALYZE и оценочный план в SSMS — да, запрос не выполняется. EXPLAIN (ANALYZE) выполняет запрос — для изменяющих данные операций оборачивайте в транзакцию с откатом. Технологический журнал всегда ограничивайте фильтром по duration, иначе переполните диск.
Почему один и тот же запрос то быстрый, то медленный?
Чаще всего — разные планы на разных значениях параметров из-за перекоса данных или устаревшая статистика. Снимите планы для «быстрого» и «медленного» случая и сравните операторы и оценки строк.