Почему СрезПоследних в 1С работает медленно и как ускорить получение данных из регистра сведений

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При работе с высоконагруженными системами на платформе 1С:Предприятие 8 программисты часто сталкиваются с тем, что стандартная виртуальная таблица СрезПоследних начинает работать крайне медленно. В регистрах с количеством записей более миллиона выполнение простого запроса может занимать 15–40 секунд, что недопустимо для оперативной работы пользователя. В этой статье мы подробно разберем, почему это происходит на уровне СУБД, и рассмотрим проверенные методы оптимизации, которые позволяют сократить время выполнения запроса с десятков секунд до сотых долей секунды.

Разберем причину: как СрезПоследних работает "под капотом"

Для начала проанализируем, почему стандартный запрос к СрезПоследних может тормозить. Рассмотрим типичный код:


ВЫБРАТЬ
    Цены.ТипЦен,
    Цены.Номенклатура,
    Цены.Цена
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ТипЦен = &ТипЦен И Номенклатура = &Номенклатура) КАК Цены

Когда платформа 1С транслирует этот запрос в язык SQL, она создает сложную конструкцию с вложенными подзапросами. На уровне СУБД это выглядит примерно так: сначала система ищет максимальную дату (MAX(Period)) для каждой комбинации измерений, входящих в фильтр, а затем выполняет соединение (INNER JOIN) полученного набора с основной физической таблицей регистра, чтобы достать ресурсы (в нашем примере — поле Цена).

Проблема заключается в том, что оптимизатор SQL Server не всегда может эффективно пробросить индексы внутрь этих вложенных конструкций. Вместо быстрого поиска по индексу (Index Seek), сервер может выбрать полное сканирование таблицы (Index Scan) или ресурсозатратное соединение типа Merge Join. Ситуация усугубляется, если статистика базы данных не актуальна или план запроса был закеширован для других параметров.

Решение №1: Использование временных таблиц для поиска максимума

Выясним, как обойти ограничения платформенного механизма. Самый эффективный способ — "разрезать" запрос на два этапа с помощью временной таблицы. Мы самостоятельно выполним поиск максимального периода, а затем соединим его с физической таблицей регистра.

Рассмотрим алгоритм реализации этого метода:

  1. Создаем временную таблицу (ВТ), в которую помещаем только измерения регистра и максимальный период.
  2. В этой же таблице прописываем условия (отборы) в секции ГДЕ.
  3. Во втором запросе пакета соединяем нашу ВТ с основной таблицей регистра по всем измерениям и периоду.

Проанализируем пример оптимизированного запроса:


// Шаг 1: Получаем последние даты по нужным измерениям
ВЫБРАТЬ
    Цены.ТипЦен,
    Цены.Номенклатура,
    МАКСИМУМ(Цены.Период) КАК Период
ПОМЕСТИТЬ ВТ_Периоды
ИЗ
    РегистрСведений.ЦеныНоменклатуры КАК Цены
ГДЕ
    Цены.Период <= &Период
    И Цены.ТипЦен = &ТипЦен
    И Цены.Номенклатура = &Номенклатура
СГРУППИРОВАТЬ ПО
    Цены.ТипЦен,
    Цены.Номенклатура;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Получаем цену, соединяясь с физической таблицей
ВЫБРАТЬ
    ВТ_Периоды.ТипЦен,
    ВТ_Периоды.Номенклатура,
    ЦеныРеальные.Цена
ИЗ
    ВТ_Периоды КАК ВТ_Периоды
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныРеальные
    ПО ВТ_Периоды.ТипЦен = ЦеныРеальные.ТипЦен
    И ВТ_Периоды.Номенклатура = ЦеныРеальные.Номенклатура
    И ВТ_Периоды.Период = ЦеныРеальные.Период

Такой подход работает быстрее по нескольким причинам. Во-первых, при работе с временной таблицей SQL Server может построить более точный план выполнения. Во-вторых, первый запрос пакета работает только с индексированными полями (измерения + период), что позволяет СУБД мгновенно найти нужные записи без обращения к данным ресурсов.

Решение №2: Анализ полей выборки и эффект Key Lookup

Рассмотрим интересный нюанс: часто бывает так, что запрос, выбирающий только измерения, работает мгновенно, но как только мы добавляем в выборку поле Цена (ресурс), начинаются тормоза. Это связано с операцией Key Lookup (или RID Lookup).

Посмотрим на ситуацию: индекс регистра обычно содержит только Период и Измерения. Значения ресурсов (цены, остатки) хранятся в основной таблице. Когда SQL находит подходящую запись в индексе, ему нужно "сбегать" в основную таблицу за ценой. Если таких записей много, сервер может решить, что проще просканировать всю таблицу целиком, чем делать тысячи мелких переходов.

Для оптимизации в этом случае стоит проверить:

Решение №3: Параметры виртуальной таблицы vs условия ГДЕ

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

  1. Внутри параметров виртуальной таблицы: Регистр.СрезПоследних(&Период, Номенклатура = &Номенклатура).
  2. В секции ГДЕ: ГДЕ Цены.Номенклатура = &Номенклатура.

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

Однако в старых версиях платформы (до 8.3.12) даже правильные параметры не всегда спасали. Если вы столкнулись с тем, что стандартная фильтрация не помогает, попробуйте передать отбор через конструкцию В (ВЫБРАТЬ...):


ИЗ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, (ТипЦен, Номенклатура) В (ВЫБРАТЬ &ТипЦен, &Номенклатура))

Иногда это "подсказывает" оптимизатору SQL правильный путь выполнения запроса.

Современный подход: Физическая таблица среза последних

Если вы используете платформу версии 8.3.12 и выше, вы можете включить специальную опцию в свойствах регистра сведений — "Разрешить итоги: Срез последних".

Разберем, как это меняет работу системы:

Рассмотрим ограничение: этот механизм работает только для получения среза на "сейчас". Если вам нужно получить данные на прошлую дату (например, вчерашнюю цену), система снова будет использовать медленный механизм вычисления через MAX(Period).

Итоговые рекомендации по оптимизации

Подведем итог нашему исследованию. Если ваш СрезПоследних начал тормозить, выполните следующие шаги:

  1. Проверьте индексы: Убедитесь, что измерения, по которым идет отбор, проиндексированы.
  2. Обновите статистику SQL: Часто проблема решается простым обслуживанием базы данных в консоли MS SQL Server.
  3. Используйте пакетные запросы: Перепишите запрос с использованием временных таблиц, как мы рассмотрели выше. Это самый надежный способ для версий 8.2 и ранних 8.3.
  4. Минимизируйте выборку ресурсов: Выбирайте только те поля (цены, количество), которые действительно нужны.
  5. Для новых платформ: Включите использование итогов для среза последних в свойствах регистра.

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

← На главную