При разработке механизмов в 1С часто возникает задача: необходимо проверить, есть ли у сотрудников, перечисленных в табличной части документа, определенные записи в регистре сведений. Начинающие разработчики часто совершают ошибку, выполняя Запрос внутри цикла обхода строк табличной части. Это приводит к серьезным проблемам с производительностью, так как каждое обращение к базе данных в цикле создает избыточную нагрузку на СУБД. Давайте разберем, как сделать это профессионально и быстро.
Главное правило оптимизации в 1С: никогда не делайте запрос внутри цикла, если можно получить те же данные за один раз. В нашем случае мы работаем со списком сотрудников, который уже есть у нас в табличной части. Вместо того чтобы спрашивать базу данных для каждого сотрудника по отдельности, мы соберем их всех в один массив или список и отправим один запрос.
Это классический и самый понятный метод. Суть его заключается в том, чтобы собрать всех сотрудников в одну коллекцию и передать её в условие ГДЕ нашего запроса.
Разберем шаги реализации:
ВыгрузитьКолонку.В в секции ГДЕ.Посмотрим, как это выглядит в коде:
// Предположим, что табличная часть называется "Сотрудники"
МассивСотрудников = Объект.Сотрудники.ВыгрузитьКолонку("Сотрудник");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РегистрСведений.СотрудникиКатегории.Сотрудник КАК Сотрудник,
| РегистрСведений.СотрудникиКатегории.Категория КАК Категория
|ИЗ
| РегистрСведений.СотрудникиКатегории КАК РегистрСведений
|ГДЕ
| РегистрСведений.Сотрудник В (&МассивСотрудников)";
Запрос.УстановитьПараметр("МассивСотрудников", МассивСотрудников);
РезультатЗапроса = Запрос.Выполнить();
Теперь в РезультатЗапроса у нас содержатся данные только по тем сотрудникам, которые есть в нашем документе. Это значительно быстрее, чем 100 запросов для 100 сотрудников.
Если проверка выполняется непосредственно в процедуре ОбработкаПроведения, мы можем поступить еще изящнее. Мы можем объединить данные нашего документа с данными регистра прямо в одном запросе.
В чем преимущество такого подхода? Мы получаем всю таблицу документа и сразу видим «пустые» места. Если запись в регистре есть, мы увидим данные, если записи нет — в поле регистра будет значение NULL.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЧ.Сотрудник,
| Регистр.Категория
|ИЗ
| Документ.НашДокумент.Сотрудники КАК ТЧ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СотрудникиКатегории КАК Регистр
| ПО ТЧ.Сотрудник = Регистр.Сотрудник
|ГДЕ
| ТЧ.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Результат = Запрос.Выполнить().Выбрать();
В этом примере ЛЕВОЕ СОЕДИНЕНИЕ позволяет нам увидеть всех сотрудников из табличной части. Те, у кого нет категории, будут иметь NULL в поле Категория, что позволит нам легко отфильтровать или обработать такие ситуации.
Часто встречается ошибка, когда разработчики пытаются использовать РегистрыСведений.ИмяРегистра.СоздатьМенеджерЗаписи() в цикле. Это антипаттерн. МенеджерЗаписи предназначен для работы с одной конкретной записью (чтение, запись или удаление). При попытке использовать его для массовой проверки система будет каждый раз обращаться к базе данных, что приведет к «тормозам» документа при проведении.
Подводя итог нашей совместной работы, запомним основные тезисы:
В с массивом параметров.ЛЕВОЕ СОЕДИНЕНИЕ в запросе позволяет за один проход получить как найденные, так и отсутствующие данные.СрезПоследних.Применяя эти простые подходы, вы сделаете ваш код не только быстрым, но и профессиональным, что существенно упростит поддержку конфигурации в будущем!