Почему обработка в 1С выполняется на одном компьютере 20 минут, а на другом — 4 часа, и как оптимизировать алгоритм проверки?

Программист 1С v8.3 (Управляемые формы) Финансы и профессиональные услуги
← На главную

При работе в клиент-серверном варианте платформы 1С:Предприятие разработчики часто сталкиваются с ситуацией, когда одна и та же обработка на разных рабочих местах показывает колоссальную разницу в скорости выполнения. В нашей практике мы разберем реальный случай из отраслевого решения «АК-Кредит» (используется микрофинансовыми организациями для автоматизации требований 115-ФЗ). Задача обработки — сопоставить список из 52 000 клиентов компании с базой террористов Росфинмониторинга.

Ситуация выглядит следующим образом: на одном компьютере документ заполняется за 20–30 минут, а на другом — этот же процесс занимает более 4 часов. При этом оба пользователя работают в тонком клиенте под полными правами, а сервер приложений 1С и сервер СУБД (SQL) разнесены на разные физические машины. Проанализируем ситуацию, выясним причины столь сильного расхождения в производительности и разберем по шагам, как оптимизировать алгоритм, чтобы ускорить его работу до нескольких секунд.

Часть 1. Выясняем причины разницы в производительности на разных ПК

Разница в скорости выполнения одной и той же серверной процедуры в 12 раз (30 минут против 4 часов) при идентичных правах пользователей не может быть вызвана только мощностью процессора клиентского компьютера. Так как код выполняется на сервере, основные причины кроются в инфраструктурных особенностях и механизме взаимодействия «Клиент - Сервер 1С - СУБД»:

  1. Сетевые задержки (Latency) между серверами: Когда сервер 1С и SQL-сервер находятся на разных физических серверах, скорость обмена пакетами между ними критически важна. Если алгоритм делает сотни тысяч мелких последовательных запросов к базе данных, то даже минимальная задержка сети (например, увеличение пинга с 0.2 мс до 1.5 мс из-за проблем с сетевой картой, коммутатором или маршрутизацией) превращает минуты ожидания в часы.
  2. Сетевое соединение «Клиент — Сервер 1С»: Если вызов процедуры происходит синхронно, а результаты обработки (огромная таблица значений на 52 000 строк с длинными текстовыми комментариями) гоняются с сервера на клиент, пропускная способность сети клиента играет решающую роль. Тонкий клиент на медленной машине, подключенной по нестабильному Wi-Fi или VPN-каналу, будет принимать этот пакет данных часами, тогда как компьютер в гигабитной локальной сети справится за секунды.
  3. Локальное антивирусное ПО: На медленном компьютере может быть активен сетевой экран или антивирусный монитор, который сканирует весь входящий трафик по портам 1540, 1541, 1560 платформы 1С или непрерывно проверяет временные файлы кэша в процессе получения тяжелого контекста формы.
  4. Диагностика сети утилитой Ping: Для исключения проблем с сетевыми пакетами на проблемной машине рекомендуется запустить команду ping с большими пакетами: ping -l 65500 IP_Адрес_Сервера_1С. Если наблюдаются потери пакетов или скачки времени отклика, проблему нужно решать на уровне сетевого оборудования.

Часть 2. Детальный технический аудит проблемного кода

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


Для Каждого ТекЛицо Из Проверяемые Цикл
    Заметки = "";
    
    // 1. Поиск в неиндексированной таблице значений в памяти
    Поиск = Террористы.НайтиСтроки(Новый Структура("ФИО", ВРЕГ(СокрЛП(ТекЛицо.Наименование))));
    
    // 2. Запрос в цикле по паспортам
    Если СтрДлина(Серия) > 0 И СтрДлина(Номер) > 0 Тогда
        СтрокаПоиска = "%" + Лев(Серия, 2) + Прав(Серия, 2) + "," + СокрЛП(Номер) + "%";
        ЗапросПаспорта.Параметры.Вставить("Паспорт", СтрокаПоиска);
        Поиск = ЗапросПаспорта.Выполнить().Выгрузить(); // Убийца производительности!
    КонецЕсли;
    
    // 3. Запрос в цикле по адресам
    СтрокаПоиска = ПолучитьСтрокуПоискаПоАдресу(ЗначенияАдреса);
    ЗапросАдреса.УстановитьПараметр("Адрес", СтрокаПоиска);
    Поиск = ЗапросАдреса.Выполнить().Выгрузить(); // Еще один запрос в цикле!
КонецЦикла;

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

Часть 3. Пошаговое руководство по исправлению алгоритма

Для того чтобы сократить время работы обработки с нескольких часов до 10–15 секунд, необходимо кардинально изменить логику сопоставления. Мы должны заставить SQL-сервер сделать всю работу за один пакетный запрос, используя механизмы временных таблиц и соединений.

Шаг 1. Перенос сопоставления на уровень СУБД

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


// Создаем менеджер временных таблиц для работы с пакетом
МВТ = Новый МенеджерВременныхТаблиц;
ЗапросОптимизированный = Новый Запрос;
ЗапросОптимизированный.МенеджерВременныхТаблиц = МВТ;

// Шаг 1.1. Выгружаем нормализованные данные проверяемых во временную таблицу
ЗапросОптимизированный.Текст = 
"ВЫБРАТЬ
|    ФизЛица.Ссылка КАК ЮрФизЛицо,
|    ВРЕГ(ПОДСТРОКА(ФизЛица.Наименование, 1, 150)) КАК ФИО_Норм,
|    ФизЛица.ДатаРождения КАК ДатаРождения,
|    ЕСТЬNULL(Паспорта.Серия, """") КАК Серия,
|    ЕСТЬNULL(Паспорта.Номер, """") КАК Номер
|ПОМЕСТИТЬ ВТ_Проверяемые
|ИЗ
|    Справочник.ФизическиеЛица КАК ФизЛица
|    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДокументыФизическихЛиц.СрезПоследних КАК Паспорта
|        ПО Паспорта.Физлицо = ФизЛица.Ссылка И Паспорта.ЯвляетсяДокументомУдостоверяющимЛичность
|ГДЕ
|    НЕ ФизЛица.ЭтоГруппа И НЕ ФизЛица.ПометкаУдаления
|;
|
|////////////////////////////////////////////////////////////////////////////////
|// Шаг 1.2. Выполняем пакетное сопоставление одним запросом к СУБД
|ВЫБРАТЬ
|    Проверяемые.ЮрФизЛицо,
|    Проверяемые.ФИО_Норм,
|    Террористы.ФИО КАК Террорист_ФИО,
|    ВЫБОР 
|        КОГДА Проверяемые.ФИО_Норм = ВРЕГ(Террористы.ФИО) И Проверяемые.ДатаРождения = Террористы.ДатаРождения 
|            ТОГДА ""Совпадение по ФИО и Дате Рождения""
|        КОГДА Проверяемые.Серия = Террористы.ПаспортСерия И Проверяемые.Номер = Террористы.ПаспортНомер
|            ТОГДА ""Совпадение по серии и номеру паспорта""
|        ИНАЧЕ """"
|    КОНЕЦ КАК РезультатПроверки
|ИЗ
|    ВТ_Проверяемые КАК Проверяемые
|    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.БазаТеррористов КАК Террористы
|        ПО Проверяемые.ФИО_Норм = ВРЕГ(Террористы.ФИО) 
|            ИЛИ (Проверяемые.Номер = Террористы.ПаспортНомер И Проверяемые.Номер <> """")";

РезультатСвязывания = ЗапросОптимизированный.Выполнить().Выгрузить();

Важное примечание: Чтобы сопоставление по паспортам работало мгновенно, предварительно нормализуйте данные в регистре БазаТеррористов при их загрузке из внешнего файла. Разделите поле «Паспорт» на отдельные колонки ПаспортСерия и ПаспортНомер без пробелов и спецсимволов. Это позволит СУБД использовать стандартные индексы B-Tree и выполнять поиск за миллисекунды.

Шаг 2. Оптимизация работы с таблицами в оперативной памяти

Если по условиям бизнес-логики часть проверок необходимо выполнять непосредственно в коде на сервере 1С, обязательно используйте индексацию коллекций в памяти. Начиная с версии платформы 8.3.13, Таблицы Значений поддерживают быстрое индексирование:


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

Для Каждого ТекЛицо Из Проверяемые Цикл
    // Теперь НайтиСтроки() работает по хэш-таблице мгновенно
    Поиск = Террористы.НайтиСтроки(Новый Структура("ФИО", ТекЛицо.ФИО_Норм));
    // ... дальнейшая постобработка
КонецЦикла;

Шаг 3. Асинхронная загрузка и порционный вывод результатов

Передача таблицы на 52 000 строк из памяти сервера в интерфейс управляемой формы тонкого клиента — тяжелая операция для рендеринга. Чтобы разгрузить клиентский компьютер:

  1. Запускайте проверку строго в фоновом задании через метод ФоновыеЗадания.Выполнить().
  2. Результаты проверки записывайте в специально созданный вспомогательный регистр сведений (например, РезультатыПроверкиПОДФТ).
  3. На управляемой форме вместо заполнения динамической таблицы значений используйте элемент интерфейса Динамический список, связанный с этим регистром сведений. Платформа 1С будет автоматически считывать и отрисовывать данные порциями (по 20-45 строк) по мере прокрутки списка пользователем, что снизит нагрузку на оперативную память клиентского ПК до минимума.

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

← На главную