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