Как оптимизировать сравнение данных между базами 1С: выбор между запросом в цикле и выгрузкой в таблицу значений

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

Сравнение данных между двумя информационными базами — задача, с которой часто сталкиваются разработчики при аудите миграций, проверке корректности обменов или сверке бухгалтерских проводок. Основная проблема здесь заключается в производительности: если данных много, стандартные подходы могут выполняться часами. Разберем на примере реальной ситуации, как оптимизировать алгоритм сверки проводок в разрезе регистраторов и почему классический "запрос в цикле" является худшим решением.

Проблема: Почему "Запрос в цикле" работает медленно?

Рассмотрим стандартную ситуацию: у нас есть список регистраторов (документов), и нам нужно проверить их движения в текущей базе и во внешней базе (например, через COM-соединение или HTTP-сервис). Первый интуитивный порыв программиста — перебрать список документов и для каждого выполнить запрос к базе данных.

Проанализируем, что происходит на техническом уровне при использовании метода Запрос.Выполнить() внутри цикла:

  1. Накладные расходы на сетевое взаимодействие: Каждый вызов запроса требует передачи текста запроса от клиента к серверу приложений, а затем к СУБД.
  2. Компиляция плана запроса: SQL-сервер каждый раз вынужден заново генерировать план выполнения, проверять права доступа и статистику таблиц.
  3. Сериализация данных: Если мы работаем с внешней базой, каждый запрос сопровождается накладными расходами на упаковку и распаковку данных (маршалинг) при передаче по протоколам обмена.

Как показывает практика, при обработке списка документов таким методом время выполнения может составлять 20 минут и более, что неприемлемо для оперативной работы.

Решение №1: Использование Таблицы Значений с индексацией

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

Важный нюанс: Чтобы поиск по этой таблице работал быстро, обязательно нужно использовать индексы. Без индексации метод НайтиСтроки() будет выполнять полный перебор таблицы для каждой записи, что сведет на нет всю выгоду от одного запроса.

Рассмотрим пример кода для подготовки такой таблицы:


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

Запрос.УстановитьПараметр("СписокРегистраторов", СписокДокументов);
ТаблицаПроводок = Запрос.Выполнить().Выгрузить();

// Добавляем индекс по полю, по которому будем искать
ТаблицаПроводок.Индексы.Добавить("Регистратор");

Использование этого метода позволяет сократить время обработки с 20 минут до 1 минуты, так как основная работа перекладывается на мощный движок SQL, а поиск в памяти 1С по индексу происходит мгновенно.

Решение №2: Гибридный метод и борьба с переполнением памяти

При очень больших объемах данных (сотни тысяч или миллионы проводок) выгрузка всей информации в одну ТаблицаЗначений может привести к чрезмерному потреблению оперативной памяти и падению рабочего процесса rphost. Выясним, как обойти это ограничение.

Оптимальным решением будет порционная обработка (батчинг). Мы разбиваем общий список регистраторов на пачки (например, по 1000 штук или по месяцам/неделям) и обрабатываем каждую пачку отдельно. Это гарантирует, что объем данных в памяти в один момент времени не превысит критического значения.

Проанализируем алгоритм гибридного метода:

  1. Разбиваем массив регистраторов на подмассивы фиксированного размера.
  2. Для каждого подмассива выполняем запрос к обеим базам.
  3. Выгружаем результаты в две временные таблицы значений.
  4. Индексируем их и сравниваем.
  5. Очищаем таблицы и переходим к следующей порции.

Решение №3: Технические приемы для экспертной оптимизации

Если проект требует максимальной производительности, стоит рассмотреть дополнительные возможности платформы 1С.

1. Использование временных таблиц (ВТ): Вместо передачи списка ссылок в условие В (&Список), можно загрузить этот список во временную таблицу и использовать ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Это позволит SQL-серверу использовать эффективные алгоритмы типа Merge Join или Hash Match.

2. Хеширование строк: Если нужно сравнивать строки проводок по 10-15 полям (счета, субконто, количество, подразделения), сравнение каждой колонки в коде 1С будет медленным. Выгоднее при выборке в запросе сформировать "ключ" строки (например, строку-конкатенацию всех значимых полей или хеш-сумму) и сравнивать только эти ключи.

3. Отказ от объектов в пользу примитивных типов: При выгрузке в ТаблицаЗначений старайтесь не выбирать ссылки на тяжелые объекты, если это не нужно. Используйте УникальныйИдентификатор или строковое представление кода/номера. Это существенно снижает "раздувание" объектного кэша памяти.

4. Асинхронность: Для очень тяжелых задач сверку можно разделить на несколько ФоновыеЗадания. Каждое задание будет обрабатывать свой период времени или свой диапазон ГУИДов, используя всю мощность многоядерных серверных процессоров.

Резюме

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

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

← На главную