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

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

Как ускорить запрос к регистру сведений в 1С

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

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

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

Определите, что именно тормозит: сам запрос или соединение

Прежде чем переписывать текст запроса, установите, где теряется время. Включите технологический журнал с событием DBMSSQL (или DBPOSTGRS, DBORACLE в зависимости от СУБД) и найдите фактический SQL-запрос с длительностью. Альтернатива — инструмент «Консоль запросов» с замером времени выполнения или расширения типа «Инструменты разработчика», показывающие план запроса.

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

Запрос выполняется секунды при малом регистреПроблема в соединениях или отсутствии индексов

План запроса: есть ли сканирование таблицы (Clustered Index Scan / Seq Scan)

СрезПоследних без параметровЧитается вся таблица регистра

Передаются ли параметры виртуальной таблицы

Запрос быстрый в консоли, медленный в кодеРазличаются параметры или контекст (РГР, RLS)

Не включены ли ограничения доступа на уровне записей

Используйте параметры виртуальных таблиц вместо отбора в ГДЕ

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

Параметры виртуальной таблицы (Период, Условие) применяются на уровне физической таблицы до построения среза. Это кардинально меняет объём чтения:

// Медленно: срез строится по всему регистру

ВЫБРАТЬ

Срез.Номенклатура,

Срез.Цена

ИЗ

РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Срез

ГДЕ

Срез.Номенклатура = &Номенклатура

// Быстро: отбор применён до построения среза

ВЫБРАТЬ

Срез.Номенклатура,

Срез.Цена

ИЗ

РегистрСведений.ЦеныНоменклатуры.СрезПоследних(

&Период,

Номенклатура = &Номенклатура) КАК Срез

Если нужен отбор по списку значений, передайте в условие временную таблицу через конструкцию «Номенклатура В (ВЫБРАТЬ ...)» или используйте параметр типа «ТаблицаЗначений» с соединением. Это всё равно дешевле, чем полный срез.

Проверьте и настройте индексы регистра

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

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

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

Сократите объём читаемых данных

Даже с правильными индексами запрос остаётся медленным, если выбирает лишнее. Три рабочих приёма:

  • Выбирайте только нужные поля. Конструкция «ВЫБРАТЬ *» и выборка всех ресурсов, когда нужен один, увеличивает и чтение с диска, и сетевой трафик между СУБД и сервером 1С.
  • Ограничивайте период. Для периодического регистра срез на конкретную дату читает заметно меньше данных, чем выборка всех записей за всё время с последующей группировкой.
  • Используйте РАЗЛИЧНЫЕ и ПЕРВЫЕ N осознанно: они уменьшают передаваемый результат, но не всегда удешевляют сам запрос — смотрите план.

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

Порядок действий при оптимизации
  1. 1
    Замерьте время выполнения исходного запроса на реальных данных
  2. 2
    Получите план запроса и найдите сканирования таблиц
  3. 3
    Перенесите отборы из ГДЕ в параметры виртуальной таблицы
  4. 4
    Проверьте индексацию полей, участвующих в условиях и соединениях
  5. 5
    Уберите лишние поля и лишние соединения из выборки
  6. 6
    Повторно замерьте время и сравните план запроса

Оптимизируйте соединения с регистром

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

  • Соединяйтесь по индексированным полям: измерение регистра к ссылке справочника — нормально; соединение по ресурсу или по вычисляемому выражению — почти всегда сканирование.
  • Не соединяйтесь с виртуальной таблицей, построенной без отборов. Сначала сузьте её параметрами.
  • Избегайте соединений через ВЫРАЗИТЬ, ПОДСТРОКУ и другие функции в условии соединения — функции отключают использование индекса.
  • ЛЕВОЕ СОЕДИНЕНИЕ с последующим отбором «ГДЕ НЕ ... ЕСТЬ NULL» заменяйте на «НЕ В (ВЫБРАТЬ ...)» только после сравнения планов — в разных СУБД поведение различается.

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

bsl
// Временная таблица с индексом ускоряет соединение с регистром
ВЫБРАТЬ
    Товары.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ_Товары
ИЗ
    &ТаблицаТоваров КАК Товары
ИНДЕКСИРОВАТЬ ПО
    Номенклатура
;
ВЫБРАТЬ
    Срез.Номенклатура,
    Срез.Цена
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
        &Период,
        Номенклатура В (ВЫБРАТЬ Т.Номенклатура ИЗ ВТ_Товары КАК Т)) КАК Срез

Учитывайте влияние RLS и режимов регистра

Ограничения доступа на уровне записей (RLS) платформа подставляет в текст запроса автоматически, и они могут радикально менять план: добавляются соединения с таблицами прав, и индексы регистра перестают использоваться эффективно. Если запрос быстрый под администратором и медленный под пользователем — почти наверняка дело в RLS. Проверяйте шаблоны ограничений и по возможности упрощайте их, вынося сложные условия в группы доступа.

Дополнительные факторы: независимый регистр сведений большого объёма без отбора по обязательным измерениям; использование регистра с подчинением регистратору там, где хватило бы независимого; включённый режим разделения итогов в файловой базе с большим числом пользователей. Каждый из этих пунктов стоит проверить, если стандартные приёмы не дали результата.

Типичные ошибки
01
СрезПоследних без параметров с фильтрацией в ГДЕ — читается вся таблица регистра
02
Соединение по неиндексированному ресурсу или реквизиту — сканирование таблицы
03
Индексация всех полей подряд — замедляется запись и раздувается база
04
Оптимизация по ощущениям без плана запроса — чинится не то место
05
Игнорирование RLS при тестировании под полными правами — на пользователях запрос снова медленный

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

Любое изменение запроса проверяйте замером, а не визуальной оценкой. Минимальный набор проверок: время выполнения на данных, близких к рабочим; план запроса до и после; поведение под пользователем с ограниченными правами. Замер делайте несколько раз — первый прогон может быть медленнее из-за холодного кэша СУБД.

Признак удачной оптимизации — не только падение времени, но и замену сканирования таблицы на поиск по индексу в плане, а также уменьшение числа логических чтений (logical reads), если ваша СУБД показывает эту статистику.

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

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

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

Снизилось в разы на рабочем объёме данных

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

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

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

Index Seek / поиск по индексу вместо сканирования

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

Осталось сканирование всей таблицы регистра

Выполнение под пользователем с RLS
Норма

Время сопоставимо с выполнением под администратором

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

Под пользователем запрос в разы медленнее

Запись в регистр после добавления индексов
Норма

Замедление записи незаметно

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

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

Часто задаваемые вопросы

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

Чаще всего условие передано в секцию ГДЕ, а не в параметры виртуальной таблицы, либо в условии используется функция над полем (например, сравнение с приведением типа), что отключает индекс. Проверьте план запроса и перенесите условие во второй параметр виртуальной таблицы.

Стоит ли индексировать ресурсы регистра сведений?

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

Что быстрее: СрезПоследних или запрос с группировкой по МАКСИМУМ(Период)?

Виртуальная таблица СрезПоследних обычно эффективнее, так как платформа генерирует для неё оптимизированный SQL с учётом индексов регистра. Ручная группировка с МАКСИМУМ и последующим соединением оправдана лишь в нестандартных сценариях, например при срезе по нескольким датам одновременно.

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

Да, если проблема в объёме данных и конкурентном доступе: серверные СУБД лучше строят планы и используют индексы на больших таблицах. Но неоптимальный запрос (срез без параметров, соединение по неиндексированным полям) останется медленным и на клиент-сервере — сначала оптимизируйте текст запроса.

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

Наиболее вероятная причина — ограничения доступа на уровне записей (RLS), которые платформа добавляет в запрос для пользователей без полных прав. Вторая возможная причина — разные значения параметров: отбор по одному элементу и по большому списку дают разные планы. Сравните фактические SQL-тексты в технологическом журнале.

Итог

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

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