При обработке больших массивов данных в 1С, например, когда ВыборкаДетальныеЗаписи содержит более миллиона элементов, программист часто сталкивается с необходимостью отслеживать текущий прогресс выполнения операции. Это важно не только для оценки оставшегося времени, но и для предотвращения «зависания» интерфейса пользователя. Разберем основные способы решения этой задачи, от простых счетчиков до продвинутых механизмов работы в фоновых заданиях.
Самый простой и очевидный способ — это создание переменной-счетчика перед началом цикла. Рассмотрим, как это выглядит в программном коде. Проанализируем пример, где мы сначала получаем общее количество записей в выборке, а затем инкрементируем счетчик на каждом шаге Следующий().
ОбщееКоличество = ВыборкаДетальныеЗаписи.Количество();
Счетчик = 0;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Счетчик = Счетчик + 1;
// Вывод информации для пользователя
Состояние("Обработано: " + Счетчик + " из " + ОбщееКоличество);
// Здесь располагается основной код обработки записи
КонецЦикла;
Этот метод отлично работает в толстом клиенте или в обычных формах. Однако при обработке 1.2 миллиона записей постоянный вызов функции Состояние() может значительно замедлить работу алгоритма из-за накладных расходов на обновление интерфейса. Поэтому рекомендуется использовать оптимизацию.
Чтобы не перегружать систему обновлением текстовой строки на каждой итерации, мы можем выводить состояние дел, скажем, каждую тысячную запись. Для этого применим оператор получения остатка от деления %. Проанализируем следующий фрагмент кода:
Если Счетчик % 1000 = 0 Тогда
Состояние("Обработано записей: " + Счетчик + " из " + ОбщееКоличество);
КонецЕсли;
Использование такого подхода позволяет сохранить высокую скорость перебора ВыборкаДетальныеЗаписи, при этом пользователь будет видеть актуальную информацию о ходе процесса с комфортной частотой обновления.
В современной платформе 1С 8.3 основной код чаще всего выполняется на сервере. Важно помнить, что метод Состояние() доступен только на клиенте. Если ваш цикл выполняется в серверном процедуре, просто вызвать его не получится. В таких случаях мы используем механизмы фоновых заданий.
Разберем алгоритм работы с фоновым заданием:
ФоновыеЗадания.Выполнить().ФоновыеЗадания.УстановитьПрогресс(Процент).Пример кода внутри цикла на сервере:
ПроцентПрогресса = (Счетчик / ОбщееКоличество) * 100;
ФоновыеЗадания.УстановитьПрогресс(ПроцентПрогресса);
Иногда возникает ситуация, когда код уже запущен, в нем не предусмотрен счетчик, а процесс длится часами (как в ситуации с 1.2 млн записей). В этом случае стандартными средствами отладки 1С прерывать выполнение нельзя, так как это остановит весь процесс. Однако мы можем выяснить статус косвенными методами:
Во-первых, если база данных клиент-серверная, мы можем воспользоваться средствами SQL Server Management Studio (SSMS). Проанализируем текущие выполняемые запросы. По активным чтениям или временным таблицам можно понять, на каком этапе находится SQL-сервер.
Во-вторых, использование Технологического журнала (ТЖ). Если настроен сбор событий DBMSSQL или SDBL, мы можем увидеть в логах, какие записи в данный момент запрашиваются из базы данных. Если выборка упорядочена, например, по дате или коду, мы легко определим «где мы сейчас».
В-третьих, консоль кластера серверов 1С. Здесь можно посмотреть объем данных, переданных сеансом, и время захвата СУБД. Это не даст точного номера итерации, но позволит оценить динамику процесса.
Если задача требует наличия номера строки непосредственно в данных, мы можем пронумеровать записи еще на этапе выполнения запроса. Хотя в языке запросов 1С нет функции ROW_NUMBER(), мы можем имитировать её через соединение таблицы самой с собой.
Рассмотрим пример логики такого запроса:
ВТ_Данные.ВТ_Данные (как Т1) с ней же (как Т2) по условию Т1.КлючевоеПоле >= Т2.КлючевоеПоле.Т1.КлючевоеПоле и рассчитываем Количество(Т2.КлючевоеПоле).В результате в ВыборкаДетальныеЗаписи у нас уже будет поле НомерСтроки, и нам не придется заводить отдельную переменную в коде 1С. Однако стоит учитывать, что для 1.2 млн записей такое соединение может быть крайне ресурсоемким.
Для профессиональной разработки рекомендуется не «изобретать велосипед», а использовать подсистему «Длительные операции» из состава БСП. Она содержит готовый программный интерфейс для запуска фоновых заданий с отображением формы прогресса, кнопкой отмены и автоматической передачей сообщений пользователю. Выясним основные преимущества этого метода:
ДлительныеОперации.СообщитьПрогресс() берет на себя всю логику взаимодействия между серверным потоком и клиентским интерфейсом.Подводя итог, можно сказать: если вам нужно просто «посмотреть» номер строки при разработке — достаточно переменной-счетчика. Если же вы создаете инструмент для пользователей, работающих с миллионами записей — используйте фоновые задания и механизмы БСП для комфортной и стабильной работы системы.