Разработка и Конфигурация · 12 мин
Как оптимизировать запросы в 1С
Практические методы оптимизации запросов 1С: индексы, виртуальные таблицы, пакетные запросы, типичные ошибки и способы проверки результата.
Медленные запросы — самая частая причина «тормозов» в 1С: отчёт формируется минутами, проведение документа занимает десятки секунд, пользователи жалуются на зависания. В большинстве случаев проблема находится не в сервере, а в самом тексте запроса: лишние соединения, отсутствие отборов по индексированным полям, обращения к виртуальным таблицам без параметров.
Оптимизация запроса в 1С — это работа на трёх уровнях: текст запроса, структура метаданных (индексы) и настройки СУБД. Начинать нужно всегда с текста запроса: он даёт эффект быстрее всего и не требует остановки системы. Ниже разобраны конкретные приёмы, которые применимы в типовых и самописных конфигурациях.
Прежде чем что-то менять, зафиксируйте исходную точку: замерьте время выполнения проблемного запроса на копии базы. Без замера «до» вы не сможете доказать, что оптимизация сработала, и не заметите, если изменение наоборот ухудшило ситуацию.
Как найти проблемный запрос и замерить его скорость
Не оптимизируйте «на глаз». Сначала определите, какой именно запрос тормозит. Для этого есть несколько инструментов: технологический журнал (ТЖ) с событиями DBMSSQL/DBPOSTGRS, консоль запросов с замером времени, а на стороне СУБД — профилировщик SQL Server (Extended Events) или pg_stat_statements для PostgreSQL.
В технологическом журнале настройте фильтр на длительность, например события дольше 2–5 секунд. В тексте события будет виден SQL-запрос и его продолжительность. Сопоставить SQL-запрос с запросом на встроенном языке помогает контекст — имя процедуры или модуля, если включён соответствующий отбор.
Для отдельного запроса в коде используйте замер через ТекущаяУниверсальнаяДатаВМиллисекундах() до и после выполнения. Это грубый, но быстрый способ сравнить варианты запроса между собой на одинаковых данных.
- 1Включите технологический журнал с фильтром по длительным событиям СУБД
- 2Воспроизведите проблемную операцию и соберите лог
- 3Найдите самый долгий запрос и сопоставьте его с кодом конфигурации
- 4Снимите план запроса в консоли СУБД или через консоль запросов
- 5Замерьте время до изменений и зафиксируйте его как базовую точку
Как читать план запроса и что в нём искать
План запроса показывает, как СУБД фактически выполняет запрос: какие индексы использует, в каком порядке соединяет таблицы, сканирует ли таблицу целиком. Получить план можно в SQL Server Management Studio (Estimated/Actual Execution Plan) или через вывод плана в консоли запросов на управляемых формах.
Главные тревожные признаки в плане: Clustered Index Scan или Table Scan по большой таблице (чтение всей таблицы вместо поиска по индексу), операции Sort и Hash Match с большим числом строк, а также предупреждения о нехватке памяти и spill в tempdb. Если вы видите сканирование таблицы движений регистра на миллионы записей — это почти наверняка причина медленной работы.
Обращайте внимание на оценку количества строк: если СУБД ожидает 100 строк, а фактически обрабатывает миллион, значит статистика устарела или запрос построен так, что оптимизатор не может правильно оценить селективность. Обновление статистики на СУБД в таком случае иногда даёт эффект без изменения запроса.
Как проверить план запроса
Index Seek по индексированным полям
Table Scan / Clustered Index Scan по большой таблице
Оценка близка к фактическому числу строк
Оценка расходится с фактом на порядки
Небольшое число строк в Sort и Hash Match
Spill в tempdb, миллионы строк в промежуточных операциях
Типовые ошибки в тексте запроса и как их исправить
Соединения с виртуальными таблицами без параметров
Виртуальные таблицы регистров (Остатки, Обороты, СрезПоследних) без указания параметров заставляют СУБД строить выборку по всей таблице движений, а уже потом фильтровать. Всегда передавайте период и условия в параметры виртуальной таблицы: РегистрНакопления.Товары.Остатки(&Период, Склад = &Склад). Условие в секции ГДЕ вместо параметра виртуальной таблицы — одна из самых дорогих ошибок.
Функции и выражения в условиях соединения
Если в условии соединения или отбора поле обёрнуто в функцию — например, ГОД(Дата) = 2026 или ПОДСТРОКА(Наименование, 1, 5) — индекс по этому полю использоваться не будет. Заменяйте такие условия на диапазоны: вместо сравнения года используйте Дата МЕЖДУ &НачалоГода И &КонецГода.
Выборка лишних полей и «ВЫБРАТЬ *»
Чем больше полей выбирает запрос, тем больше данных читается с диска и передаётся по сети. Убирайте поля, которые не используются в дальнейшей обработке, особенно поля неограниченной длины (строки, ХранилищеЗначения). Разворачивание ссылок через точку («Товары.Номенклатура.Артикул») тоже порождает скрытые соединения — выбирайте реквизиты явно и только нужные.
Как индексы влияют на скорость и когда их добавлять
1С автоматически создаёт индексы по измерениям регистров, ключам справочников и полям с признаком «Индексировать». Если запрос фильтрует по реквизиту без индекса, СУБД вынуждена сканировать таблицу. Проверьте в конфигураторе свойства реквизита: для часто используемых в отборах полей включите индексирование.
Для составных условий важен порядок полей в индексе: индекс работает, когда в отборе участвуют поля с начала списка. Если отбор идёт по Складу и Номенклатуре, а индекс построен как (Номенклатура, Склад), эффект будет слабым. В типовых регистрах порядок измерений менять рискованно — это влияет на всю логику, поэтому сначала пробуйте перестроить запрос под существующий индекс.
Помните и об обратной стороне: каждый дополнительный индекс замедляет запись (проведение документов) и занимает место. Не добавляйте индексы «про запас» — только под подтверждённый замером запрос.
Пакетные запросы и временные таблицы
Если запрос соединяет несколько больших выборок, часто выгоднее разбить его на пакет: сначала отобрать нужные данные во временную таблицу с фильтром, проиндексировать её, а затем соединять с остальными. Временная таблица уменьшает объём данных в соединениях с миллионов строк до тысяч.
После создания временной таблицы добавьте ИНДЕКСИРОВАТЬ ПО по полям, которые участвуют в последующих соединениях — иначе соединение с ней снова уйдёт в сканирование. И не забывайте уничтожать временные таблицы (УНИЧТОЖИТЬ) или использовать МенеджерВременныхТаблиц с явным временем жизни, чтобы не копить данные на сервере.
Пакетный подход особенно эффективен, когда один и тот же отбор используется в нескольких соединениях: вместо повторного построения виртуальной таблицы трижды вы строите её один раз и переиспользуете.
ВЫБРАТЬ Товары.Номенклатура, Товары.Количество ПОМЕСТИТЬ ВТ_Отбор ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Товары ИНДЕКСИРОВАТЬ ПО Товары.Номенклатура; ВЫБРАТЬ ВТ.Номенклатура, ВТ.Количество, Спр.Артикул ИЗ ВТ_Отбор КАК ВТ ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Спр ПО ВТ.Номенклатура = Спр.СсылкаСоединения, подзапросы и УСЛОВИЕ В: что выбрать
Частая дилемма — фильтровать через соединение, вложенный запрос или оператор В (ВЫБРАТЬ ...). На практике для больших таблиц предпочтительнее соединение с временной таблицей: оптимизатор СУБД работает с ней предсказуемее, чем со вложенным подзапросом в условии В. Подзапросы в секции ГДЕ на некоторых СУБД приводят к выполнению подзапроса для каждой строки основной выборки.
Условие В ИЕРАРХИИ(&Группа) по справочнику — отдельный случай: оно порождает рекурсивную логику на уровне платформы. Если отбор по иерархии выполняется внутри большого запроса многократно, выгоднее заранее вычислить список элементов группы во временную таблицу и соединяться с ней.
Левые соединения с последующей проверкой «ЕСТЬ NULL» для поиска отсутствующих записей — рабочий приём, но на больших таблицах иногда быстрее использовать НЕ В с предварительно материализованной временной таблицей. Единственный надёжный способ выбрать — замерить оба варианта на ваших данных.
Способы фильтрации данных
Лучший вариант для больших таблиц: предсказуемый план, можно проиндексировать. Требует пакетного запроса и менеджера временных таблиц
Подходит для небольших выборок и простых условий. На больших данных может выполняться неэффективно
Обязательный вариант для регистров: самый быстрый способ ограничить выборку на уровне построения таблицы
Уровень СУБД и платформы: что ещё проверить
Если текст запроса и индексы в порядке, а запрос всё равно медленный — смотрите на инфраструктуру. Устаревшая статистика и фрагментированные индексы на СУБД регулярно дают деградацию производительности. Регламентное обновление статистики и реиндексация должны выполняться по расписанию, особенно на базах с интенсивной записью.
Проверьте настройки базы: для MS SQL рекомендуется режим совместимости, соответствующий версии, и включённый параметр AUTO_UPDATE_STATISTICS_ASYNC в ряде сценариев. На стороне платформы обратите внимание на версию — в новых релизах платформы регулярно улучшается генерация SQL для виртуальных таблиц.
Наконец, иногда «медленный запрос» — это симптом блокировок, а не самого запроса. Если запрос быстрый в консоли, но медленный в работе пользователей, анализируйте взаимоблокировки и ожидания на блокировках в технологическом журнале. Управляемый режим блокировок и сокращение транзакций часто решают проблему без правки запросов.
Как выбрать действие
Что важно запомнить
Оптимизация начинается с замера и плана запроса, а не с догадок. Основной эффект дают: параметры виртуальных таблиц, корректные индексы, отказ от функций в условиях, временные таблицы с индексацией и выборка только нужных полей. Изменения структуры — только на копии базы с резервной копией. Если запрос быстр в консоли, но медленен в работе — ищите блокировки.
Частые вопросы
Нужно ли всегда использовать временные таблицы вместо вложенных запросов?
Нет. Для небольших выборок вложенный запрос проще и не уступает по скорости. Временные таблицы оправданы, когда промежуточный результат большой, используется в нескольких соединениях или требует индексации. Решение принимайте по замеру на реальных данных.
Почему запрос с одинаковым текстом работает по-разному на разных базах?
План запроса зависит от объёма данных, статистики и фрагментации индексов. На копии базы со свежей статистикой запрос может летать, а на рабочей — сканировать таблицы. Поэтому оптимизацию проверяйте на данных, максимально близких к рабочим, и поддерживайте регламент обновления статистики.
Можно ли добавить индекс напрямую в SQL Server, не меняя конфигурацию?
Технически можно, но делать этого не стоит: при обновлении конфигурации платформа может пересоздать таблицы, и индекс потеряется, а рассинхронизация структуры затруднит поддержку. Правильный путь — включить индексирование реквизита в конфигураторе или использовать индексы с дополнительными полями, предусмотренные платформой.
Влияет ли отключение итогов на скорость запросов к регистрам?
Да. Если итоги регистра накопления отключены, виртуальные таблицы остатков строятся расчётом по таблице движений, что на больших объёмах существенно медленнее. Для активно используемых регистров итоги должны быть включены, а период рассчитанных итогов — актуальным.
Как понять, что проблема в блокировках, а не в самом запросе?
Признак: запрос быстро выполняется в консоли, но «висит» при работе пользователей, причём время растёт при увеличении нагрузки. Подтверждение ищите в технологическом журнале по событиям TLOCK и TDEADLOCK, а на СУБД — по ожиданиям на блокировках. Лечится сокращением транзакций, управляемым режимом блокировок и порядком обращения к таблицам.
Что даёт конструкция «ДЛЯ ИЗМЕНЕНИЯ» и когда её применять?
Она устанавливает управляемую блокировку на читаемые данные до конца транзакции, защищая от конкурентного изменения. Применяйте только внутри транзакции и только когда данные действительно будут меняться: избыточное использование «ДЛЯ ИЗМЕНЕНИЯ» усиливает конкуренцию за блокировки и замедляет параллельную работу.