← Назад к вопросам

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

3.0 Senior🔥 201 комментариев
#Запросы и оптимизация

Условие

Оптимизируйте следующий запрос по производительности:

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

Подсказка

Обратите внимание на:

  • Обращение к реквизитам через точку
  • Условие в секции ГДЕ для виртуальной таблицы
  • Использование конструкций ВЫРАЗИТЬ и ССЫЛКА для оптимизации

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

Это классическая задача оптимизации 1С-запросов. Исходный запрос имеет несколько проблем, которые негативно влияют на производительность. Рассмотрим их и предложим решение.

Проблемы исходного запроса

1. Обращение через точку к реквизитам справочника

Цены.Номенклатура.Наименование КАК НаименованиеТовара,
Цены.Номенклатура.Артикул КАК Артикул,

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

2. СрезПоследних() выполняется на БД

Виртуальная таблица СрезПоследних() — это дорогая операция, если её параметры не оптимальны.

3. Условие на реквизит справочника в ГДЕ

Сопоставление через .Родитель требует дополнительных операций СУБД.

Оптимизированное решение

Процедура ПолучитьЦеныОптимизировано(ГруппаНоменклатуры)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    Номенклатура.Наименование КАК НаименованиеТовара,
        |    Номенклатура.Артикул КАК Артикул,
        |    ЦеныПоследние.Цена
        |ИЗ
        |    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, Номенклатура ССЫЛКА Справочник.Номенклатура) КАК ЦеныПоследние
        |ЛЕВОЕ СОЕДИНЕНИЕ
        |    Справочник.Номенклатура КАК Номенклатура
        |ПО
        |    ЦеныПоследние.Номенклатура = Номенклатура.Ссылка
        |ГДЕ
        |    Номенклатура.Родитель = &ГруппаНоменклатуры
        |    И НЕ Номенклатура.ПометкаУдаления
        |УПОРЯДОЧИТЬ ПО
        |    Номенклатура.Наименование";
    
    Запрос.УстановитьПараметр("ГруппаНоменклатуры", ГруппаНоменклатуры);
    
    Результат = Запрос.Выполнить().Выбрать();
    
КонецПроцедуры

Альтернативное решение (ещё более оптимальное)

Процедура ПолучитьЦеныЧерезЗапросКоллекции(ГруппаНоменклатуры)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    НоменклатураПовиток.Ссылка КАК НоменклатураСсылка
        |ИЗ
        |    Справочник.Номенклатура КАК НоменклатураПовиток
        |ЛЕВОЕ СОЕДИНЕНИЕ
        |    Справочник.Номенклатура КАК НоменклатураРодитель
        |ПО
        |    НоменклатураПовиток.Родитель = НоменклатураРодитель.Ссылка
        |ГДЕ
        |    НоменклатураПовиток.Родитель = &ГруппаНоменклатуры
        |    И НЕ НоменклатураПовиток.ПометкаУдаления";
    
    Запрос.УстановитьПараметр("ГруппаНоменклатуры", ГруппаНоменклатуры);
    
    РеквизитыНоменклатуры = Новый ТаблицаЗначений;
    РеквизитыНоменклатуры.Колонки.Добавить("Ссылка");
    РеквизитыНоменклатуры.Колонки.Добавить("Наименование");
    РеквизитыНоменклатуры.Колонки.Добавить("Артикул");
    РеквизитыНоменклатуры.Колонки.Добавить("Цена");
    
    НоменклатураСсылки = Запрос.Выполнить().ВыгрузитьКолонку("НоменклатураСсылка");
    
    // Получаем последние цены только для отобранных товаров
    ЗапросЦены = Новый Запрос;
    ЗапросЦены.Текст = 
        "ВЫБРАТЬ
        |    Цены.Номенклатура,
        |    Цены.Цена
        |ИЗ
        |    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, Номенклатура В(&МассивНоменклатуры)) КАК Цены";
    
    ЗапросЦены.УстановитьПараметр("МассивНоменклатуры", НоменклатураСсылки);
    
    ТаблицаЦен = ЗапросЦены.Выполнить().ВыгрузитьВТаблицу();
    
КонецПроцедуры

Решение 3: Кэширование в памяти (для часто вызываемых данных)

ПеременнаяКэш.ЦеныНоменклатуры = Неопределено;
ПеременнаяКэш.ВремяОбновления = '00010101';

Процедура ПолучитьЦеныСКэшем(ГруппаНоменклатуры)
    
    // Проверяем кэш (кэшируем 5 минут)
    ТекущееВремя = ТекущаяДата();
    
    Если ПеременнаяКэш.ЦеныНоменклатуры <> Неопределено 
        И ТекущееВремя - ПеременнаяКэш.ВремяОбновления < 300 Тогда
        Возврат ПеременнаяКэш.ЦеныНоменклатуры;
    КонецЕсли;
    
    // Выполняем оптимизированный запрос
    Результат = ПолучитьЦеныОптимизировано(ГруппаНоменклатуры);
    
    // Обновляем кэш
    ПеременнаяКэш.ЦеныНоменклатуры = Результат;
    ПеременнаяКэш.ВремяОбновления = ТекущееВремя;
    
    Возврат Результат;
    
КонецПроцедуры

Ключевые оптимизации

  1. Явное СОЕДИНЕНИЕ — вместо обращения через точку
  2. Фильтр ССЫЛКА в СрезПоследних() — указываем тип данных явно
  3. ЛЕВОЕ СОЕДИНЕНИЕ — получаем реквизиты из справочника
  4. Добавлена сортировка — для удобства и предсказуемости
  5. Кэширование — для часто используемых данных

Сравнение производительности

ПодходСкоростьЗатраты памятиСложность
Исходный запросМедленноСредниеПростой
Оптимизация 1БыстроСредниеСредняя
Оптимизация 2Очень быстроСредниеВысокая
С кэшемОчень быстроВысокиеВысокая

Рекомендация

Используйте Решение 1 (ЛЕВОЕ СОЕДИНЕНИЕ) — это оптимальный баланс между производительностью и простотой кода. Если запрос вызывается часто и данные стабильны, добавьте кэширование.