К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как ускорить выполнение запроса в 1С

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

Медленный запрос в 1С — одна из самых частых причин жалоб пользователей на «тормоза» отчётов, проведения документов и обменов данными. При этом в большинстве случаев проблема решается не покупкой более мощного сервера, а грамотной переработкой самого запроса и структуры данных, к которым он обращается.

Оптимизация начинается с диагностики: нужно понять, какая часть запроса отнимает время, какие таблицы сканируются целиком и какие индексы реально используются СУБД. Только после этого имеет смысл переписывать текст запроса, добавлять индексы или менять архитектуру решения.

Ниже разобраны практические приёмы: от анализа плана запроса до работы с виртуальными таблицами и временными таблицами. Материал ориентирован на разработчиков и администраторов 1С, работающих с клиент-серверными базами (MS SQL, PostgreSQL), но большинство рекомендаций применимы и к файловому режиму.

Как найти узкое место: замер и план запроса

Первый шаг — воспроизвести проблему и измерить, сколько времени занимает именно запрос, а не окружающий его код. Для этого используйте замер производительности в конфигураторе (Отладка → Замер производительности) или инструмент «Замеры производительности» в технологическом журнале. Важно отделить время выполнения запроса на сервере СУБД от времени обхода результата в коде.

Для клиент-серверных баз ключевой инструмент — план выполнения запроса. В MS SQL его можно получить через SQL Server Management Studio, в PostgreSQL — через EXPLAIN ANALYZE. План показывает, как СУБД исполняет запрос: читает ли она таблицу целиком (сканирование) или находит записи по индексу, какие соединения выполняются и в каком порядке.

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

Запрос выполняется секунды, таблица небольшаяВероятен проблемный код вокруг запроса

Проверьте обход результата в цикле и запросы внутри цикла

План показывает сканирование таблицы движенийНе используется индекс

Проверьте условия отбора и состав существующих индексов

Запрос быстрый в тесте, медленный в работеПроблема в объёме данных или блокировках

Снимите план на рабочей базе и проверьте ожидания на блокировках

Оптимизация текста запроса на встроенном языке

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

Избегайте функций и выражений над полями в условиях соединений и отборов: конструкции вида ПОДСТРОКА(Таблица.Код, 1, 5) = &Префикс или НАЧАЛОПЕРИОДА(Таблица.Дата, ДЕНЬ) = &Дата мешают использовать индекс по полю. Если возможно, вычислите значение заранее и сравнивайте поле с параметром напрямую.

Не выбирайте лишние поля и лишние строки. Если нужны только существующие записи, используйте ВЫБРАТЬ ПЕРВЫЕ 1 вместо полной выборки с проверкой количества. Если нужен только факт наличия данных, часто достаточно запроса с ИТОГИ или проверки Результат.Пустой() по минимальной выборке.

Типичные ошибки в тексте запроса
01
Условия накладываются на результат соединения, а не на исходные таблицы — СУБД обрабатывает лишние миллионы строк
02
Использование функций над полями в условиях — индекс перестаёт применяться, начинается полное сканирование
03
Соединение с виртуальной таблицей без параметров — строится выборка по всему регистру за всё время
04
Выбор всех полей «про запас» — растёт объём передаваемых данных и время сортировки

Индексы: что проверить и как добавить

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

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

Помните о цене индексов: каждый индекс замедляет запись и занимает место. Не добавляйте индексы «на всякий случай» — создавайте их под конкретные частые запросы и проверяйте эффект по плану выполнения до и после изменения.

Работа с виртуальными таблицами и временными таблицами

Виртуальные таблицы регистров (Остатки, Обороты, СрезПоследних) — частый источник проблем. Без параметров они строятся по всем данным регистра. Всегда передавайте параметры: период, условия по измерениям. Например, РегистрНакопления.Товары.Остатки(&Дата, Склад = &Склад) выполнится на порядки быстрее, чем та же таблица без отбора с фильтрацией после соединения.

Для сложных запросов используйте пакетные запросы с временными таблицами: сначала отберите узкий набор данных во временную таблицу, проиндексируйте её по полям соединения, затем соединяйте с остальными данными. Это даёт оптимизатору СУБД понятную структуру и часто ускоряет выполнение в разы.

Порядок оптимизации сложного запроса
  1. 1
    Снимите замер и план запроса, найдите самую дорогую операцию
  2. 2
    Вынесите отборы в параметры виртуальных таблиц и ранние временные таблицы
  3. 3
    Проиндексируйте временные таблицы по полям соединений
  4. 4
    Проверьте, что условия не содержат функций над индексируемыми полями
  5. 5
    Повторно снимите план и убедитесь, что сканирование заменено поиском по индексу

Запросы в циклах, блокировки и окружение

Классическая ошибка — выполнение запроса внутри цикла по строкам таблицы значений. Даже быстрый запрос, вызванный тысячу раз, даст неприемлемое суммарное время. Решение: собрать данные цикла во временную таблицу и выполнить один запрос с соединением, либо использовать конструкцию Значение(Таблица...) через параметр-таблицу.

Если запрос сам по себе оптимален, но в рабочей базе «подтормаживает», проверьте блокировки. Длительные транзакции на запись удерживают управляемые блокировки, и читающие запросы вынуждены ждать. Признаки — ожидания на блокировках в технологическом журнале, рост времени выполнения в часы активной работы пользователей.

Не забывайте про обслуживание СУБД: устаревшая статистика и фрагментированные индексы приводят к тому, что оптимизатор выбирает неудачный план. Регулярное обновление статистики и перестроение индексов на уровне СУБД — обязательная часть поддержки крупных баз, это задача администратора, а не разработчика запроса.

Маршрут решения

Как выбрать действие

План показывает сканирование большой таблицыДобавьте или скорректируйте индекс, уберите функции над полями отбора
Медленно строится виртуальная таблицаПередайте период и условия в параметры виртуальной таблицы
Запрос вызывается в циклеСоберите данные во временную таблицу и выполните один запрос
Запрос быстрый в тесте, но медленный в работеПроверьте блокировки, статистику СУБД и актуальность плана
Всё оптимизировано, но данных слишком многоРассмотрите итоги, агрегатные таблицы или перенос расчёта в фоновые задания

Проверка результата и альтернативные подходы

Любую оптимизацию завершайте контрольным замером на данных, близких к рабочим по объёму. Сравните время выполнения и план запроса до и после изменений. Убедитесь, что результат запроса не изменился: оптимизация не должна менять состав возвращаемых данных, если это не было целью доработки.

Если запрос упирается в физический объём данных, переписывание текста уже не поможет. В таких случаях рассмотрите: использование итогов регистров вместо пересчёта «на лету», предварительное заполнение агрегатных таблиц фоновыми заданиями, вынос тяжёлых отчётов на ночное выполнение или на копию базы, включение стандартного механизма копий базы данных для отчётной нагрузки.

Контрольные точки

Как проверить результат

Время выполнения запроса
Норма

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

Тревожный признак

Изменилось незначительно или выросло

План запроса
Норма

Поиск по индексу вместо сканирования таблиц

Тревожный признак

Сканирование больших таблиц сохранилось

Состав результата
Норма

Данные идентичны исходному запросу

Тревожный признак

Пропали или появились строки

Работа пользователей
Норма

Нет жалоб на блокировки после добавления индексов

Тревожный признак

Замедлилась запись документов

Итог

Что важно запомнить

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

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

Можно ли ускорить запрос без изменения конфигурации?

Частично да: обновление статистики и перестроение индексов на уровне СУБД, настройка регламентных заданий обслуживания и устранение блокировок могут дать эффект без доработки кода. Но если проблема в самом тексте запроса или отсутствии индекса по реквизиту, без изменения конфигурации не обойтись.

Почему запрос быстрый на копии базы и медленный на рабочей?

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

Всегда ли нужно индексировать временные таблицы?

Нет. Индекс по временной таблице оправдан, когда она содержит заметное количество строк и участвует в соединениях по конкретным полям. Для маленьких таблиц на несколько десятков строк индекс не даст выигрыша и лишь добавит затрат на его построение.

Что лучше: один большой запрос или несколько маленьких?

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

Поможет ли переход на более мощный сервер?

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

Опасно ли добавлять индексы в типовую конфигурацию?

Добавление индекса через свойство «Индексировать» меняет конфигурацию и может усложнить обновление, если меняются типовые объекты. Безопаснее сначала проверить эффект на тестовой базе, зафиксировать изменения и учитывать их при обновлениях. Сам индекс не влияет на логику данных, только на скорость чтения и записи.