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

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

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

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

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

Задача: рассчитать строки заказа по ценам на 5 сентября 2026 года, 12:00. Работаем в отдельной учебной базе. Один товар может повторяться в нескольких строках. Если хотя бы для одной позиции цены нет, нужно остановиться, не изменив ни одной суммы.

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

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

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

Подготовьте данные, на которых видна разница

Создайте неиерархический справочник «Номенклатура»: «Кабель», «Крепёж», «Стойка». Создайте независимый периодический регистр сведений «ЦеныНоменклатуры» с периодичностью «В пределах секунды». Единственное измерение — «Номенклатура», тип СправочникСсылка.Номенклатура; ресурс «Цена» — число 10,2, неотрицательное.

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

Учебная история цен: все времена указаны в одной временной зоне базы
ПериодНоменклатураЦена
01.09.2026 00:00:00Кабель200
05.09.2026 00:00:00Кабель240
06.09.2026 00:00:00Кабель999
01.09.2026 00:00:00Крепёж60

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

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

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

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

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

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

Поместите функцию в общий модуль «УчебныйРасчет» с флагом «Сервер», без флага «Глобальный». Она принимает серверную ТаблицуЗначений с колонками «Номенклатура» (ссылка на справочник), «Количество» (число 10,0) и «Сумма» (число 15,2). Это не обработчик клиентской формы и не готовое изменение типовой конфигурации.

После разбора: один запрос и проверка всех цен до изменения сумм
// Общий модуль УчебныйРасчет: Сервер, без флага «Глобальный».
Функция РассчитатьСтроки(Товары, ДатаСреза) Экспорт
    Если Товары.Количество() = 0 Тогда
        Возврат 0;
    КонецЕсли;

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

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

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

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

    Для Индекс = 0 По Товары.Количество() - 1 Цикл
        Товары[Индекс].Сумма = НовыеСуммы[Индекс];
    КонецЦикла;
    Возврат Итог;
КонецФункции

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

На сервере создайте таблицу из трёх строк: «Кабель», количество 2; «Крепёж», количество 3; «Кабель», количество 1. Во всех суммах до расчёта поставьте 777 — так будет видно, какие значения изменились. Передавайте ссылки на товары, не строки с названиями.

Вызовите УчебныйРасчет.РассчитатьСтроки(Товары, Дата(2026, 9, 5, 12, 0, 0)). Ожидаем суммы 480, 180 и 240; возвращённый итог — 900. Для проверки ошибки восстановите 777 во всех строках и замените товар последней строки на «Стойку»: должно возникнуть исключение, а все три суммы остаться равными 777.

Арифметика и крайние случаи сверены автоматическими тестами отдельной модели расчёта. Сам код 1С здесь приведён для запуска в учебной базе; замеры времени и выполнение на вашей версии платформы нужно проверить отдельно. Обещать ускорение в секундах без такого измерения было бы неправильно.

Ожидаемые результаты для указанных учебных данных
ПроверкаРезультатВызовы Выполнить
Три исходные строки480 + 180 + 240 = 900До: 3; после: 1
Пустая таблицаИтог 00
Последняя строка — Стойка без ценыОшибка; исходные суммы не изменены1
Цена Крепежа заменена на 0480 + 0 + 240 = 720: нулевая цена допустима1
Пустая номенклатура или количество 0Ошибка до запроса; суммы не изменены0
100 одинаковых строк Кабеля по 1Итог 24 000; один товар в отбореДо: 100; после: 1

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

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

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

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

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

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

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

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

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

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

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

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

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

·

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

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

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

Telegram ↗ VK ↗

Шаг 4 из 5

Данные в 1С: как выбирать значения, читать и проверять результат

Перейдите к самостоятельному отчёту: сверяйте группы и суммы с небольшим контрольным набором.

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

Теперь попробуйте найти ошибку самостоятельно

В тренажёре код-ревью — 50 бесплатных заданий на поиск ошибок в чужом коде. Отметьте проблемные строки, объясните причину и сравните результат с проверкой. Это самостоятельная тренировка, не проверка вашей работы ментором.

Нужен бесплатный вход. AI-раздел и практика с проверкой ментором имеют отдельные условия доступа. В «1С код» действуют лимиты попыток и восстановление жизней.
Открыть тренажёр код-ревью →