Публичный пример работы

Пример разбора кода 1С:
как исправить запрос внутри цикла

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

Фрагмент разбора кода 1С с запросом, который выполняется внутри цикла
  • Исходный учебный фрагмент с понятной проблемой
  • Комментарии проверяющего по скорости и правильности работы
  • Вариант исправления без запроса на каждом проходе цикла
  • Список повторной проверки после изменения кода
Содержание

Условие учебного примера

Задача простая: рассчитать сумму строк табличной части по последним зарегистрированным ценам. Названия объектов здесь условные. В реальной конфигурации нужно взять объекты проекта и отдельно проверить правила получения цены.

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

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

    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        СтрокаТовара.Сумма = СтрокаТовара.Количество * Выборка.Цена;
    КонецЕсли;
КонецЦикла;

Что я отмечу при проверке

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

Есть и вторая проблема: мы не решили, что делать, если цена не найдена. Оставить ноль, показать предупреждение или остановить расчёт? Это нужно согласовать до изменения кода, иначе ускорение незаметно поменяет поведение системы.

  • Зафиксировать число строк и число обращений к данным до изменения.
  • Уточнить момент среза и правила выбора вида цены.
  • Определить поведение для пустой номенклатуры и отсутствующей цены.
  • Не переносить расчёт на клиент только ради визуального ускорения.

Как можно исправить

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

После разбора: одна выборка цен и явная проверка отсутствующих значений
НоменклатураДляЗапроса = Новый Массив;
Для Каждого СтрокаТовара Из Товары Цикл
    Если ЗначениеЗаполнено(СтрокаТовара.Номенклатура)
        И НоменклатураДляЗапроса.Найти(СтрокаТовара.Номенклатура) = Неопределено Тогда
        НоменклатураДляЗапроса.Добавить(СтрокаТовара.Номенклатура);
    КонецЕсли;
КонецЦикла;

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

    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        ЦеныПоНоменклатуре.Вставить(Выборка.Номенклатура, Выборка.Цена);
    КонецЦикла;
КонецЕсли;

Для Каждого СтрокаТовара Из Товары Цикл
    Цена = ЦеныПоНоменклатуре.Получить(СтрокаТовара.Номенклатура);
    Если Цена = Неопределено Тогда
        ВызватьИсключение "Для позиции не найдена цена";
    КонецЕсли;
    СтрокаТовара.Сумма = СтрокаТовара.Количество * Цена;
КонецЦикла;

Как проверить исправление

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

  • Пустая табличная часть не вызывает ошибку и не делает лишний запрос.
  • Повторяющаяся номенклатура попадает в набор запроса один раз.
  • Отсутствующая цена обрабатывается согласованным способом.
  • Сумма совпадает с исходным вариантом на корректных данных.
  • Количество запросов не зависит от количества строк документа.

Как выглядит полезный разбор кода

Полезное замечание отвечает на четыре вопроса: что я увидел, чем это опасно, как повторить проблему и по какому признаку принять исправление. Фраза «перепиши запрос» ничему не учит. А формулировка «сейчас выполняется один запрос на строку; получи данные одним обращением и покажи проверку отсутствующей цены» оставляет понятную задачу для самостоятельной работы.

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

Самопроверка

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

Почему нельзя просто оставить запрос в цикле?

На малом наборе это может быть незаметно, но число обращений к базе растёт вместе с количеством строк. Один наборный запрос обычно предсказуемее и легче измеряется.

Можно ли копировать исправленный код в рабочую конфигурацию?

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

Что важнее при разборе: стиль или скорость работы?

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

Первичные источники

Что проверить дополнительно

Полезный материал

Поделиться статьёй

Сохраните материал или отправьте его тому, кому он пригодится.

Следующий шаг

Хотите получать разбор собственных решений?

Посмотрите, как в менторстве устроены практика, повторная попытка и ручная проверка.

Посмотреть формат разбора →