Play
online · 30 мин
← все статьи
Туториалы 17 мин чтения 13.05.2026

Тормозит обмен 1С с Битрикс: замер через события, 5 причин и как ускорить

Импорт 80 000 товаров из 1С в Битрикс занимал 6 часов, а после профилирования сократился до 40 минут. Разбираем 5 главных причин тормозов: обработчики событий, отсутствие индексов и блокировки транзакций. Узнайте, как замерить узкие места и ускорить обмен без гаданий.

Главные выводы за 30 секунд

Когда к нам приходят с задачей «ускорить обмен 1С с Битрикс», первое, что мы делаем — не лезем в настройки модуля, а замеряем время. Без цифр любая оптимизация — гадание. У нас в практике был проект с 80 000 товаров: импорт длился 6 часов, а после профилирования и точечных правок, 40 минут. В этой секции, суть для занятых: пять причин тормозов, с которых стоит начать диагностику.

  • Обработчики событий, кастомный код в OnBeforeCatalogImport1C или OnAfterIBlockElementUpdate, который выполняется для каждого элемента и жрёт время.
  • Отсутствие индексов, запросы к таблицам b_iblock_element_property или b_catalog_price без индексов превращают импорт в полный table-scan.
  • Транзакции, каждая операция внутри транзакции блокирует таблицы; если одна партия импорта обновляет 500 элементов, блокировка держится минутами.
  • Кеш, сброс всего кеша после каждого шага импорта (например, через CIBlock::ClearCache()), самая частая ошибка, которую мы видим у клиентов.
  • Неоптимальные запросы, CIBlockElement::GetList() с GetNextElement() в цикле вместо одного SQL-запроса с джойнами.

Как замерить время импорта 1С с помощью событий

Помню случай на проекте с каталогом на 30 тысяч SKU: импорт из 1С отрабатывал стабильно, но менеджеры жаловались, что товары на сайте обновляются «вдруг через час». Стандартные логи Битрикса писали только «импорт завершён», без разбивки по шагам. Мы тогда впервые и задумались — а где именно теряется время? Оказалось, что движок предоставляет удобные события OnBeforeCatalogImport1C и OnAfterCatalogImport1C, а также их пары для каждого этапа обмена. Если замерить время между ними и записать в лог, на выходе получаем точную картину: какой шаг — авторизация, загрузка XML, разбор или обновление элементов, реально тормозит. В этой секции покажем, как быстро навесить замер на существующий импорт без доработки модуля обмена.

События OnStart и OnEnd для каждого шага импорта

У нас в практике чаще всего используют четыре пары событий. OnBeforeCatalogImport1C / OnAfterCatalogImport1C, оборачивают всю сессию целиком, от первого запроса до финального коммита. Для детализации смотрим на шаги: OnBeforeIBlockElementAdd / OnAfterIBlockElementAdd ловят момент добавления каждого нового товара, а OnBeforeIBlockElementUpdate / OnAfterIBlockElementUpdate, обновление существующих. Отдельно стоит OnBeforeIBlockSectionAdd с парой, если импорт создаёт разделы. Важно: события стреляют внутри транзакции импорта, поэтому код замера должен быть лёгким, никаких curl или долгих запросов к внешним API.

PHP
// init.php
use Bitrix\Main\EventManager;
use Bitrix\Main\IO\File;

$eventManager = EventManager::getInstance();
$logFile = $_SERVER['DOCUMENT_ROOT'] . '/upload/import_time.log';

// Замер всей сессии
$eventManager->addEventHandler('catalog', 'OnBeforeCatalogImport1C', function() use ($logFile) {
        $start = microtime(true);
        File::putContents($logFile, date('Y-m-d H:i:s') . " SESSION_START {$start}\n", FILE_APPEND);
});

$eventManager->addEventHandler('catalog', 'OnAfterCatalogImport1C', function() use ($logFile) {
        $end = microtime(true);
        File::putContents($logFile, date('Y-m-d H:i:s') . " SESSION_END {$end}\n", FILE_APPEND);
});

// Замер обновления каждого элемента
$eventManager->addEventHandler('iblock', 'OnBeforeIBlockElementUpdate', function(&$arFields) use ($logFile) {
        $start = microtime(true);
        File::putContents($logFile, date('Y-m-d H:i:s') . " ELEMENT_UPDATE_START {$arFields['ID']} {$start}\n", FILE_APPEND);
});

$eventManager->addEventHandler('iblock', 'OnAfterIBlockElementUpdate', function($elementId) use ($logFile) {
        $end = microtime(true);
        File::putContents($logFile, date('Y-m-d H:i:s') . " ELEMENT_UPDATE_END {$elementId} {$end}\n", FILE_APPEND);
});

Ключевое в этом коде, мы не останавливаем импорт, а просто пишем метку времени в файл. Внутри OnBeforeIBlockElementUpdate передаются поля элемента как ссылка (&$arFields), поэтому нельзя случайно сломать обновление, только читаем $arFields['ID']. microtime(true) даёт точность до микросекунд, что важно, если шаг длится доли секунды. Если импорт идёт в несколько потоков, лучше добавить в лог идентификатор сессии, у нас для этого используется session_id() или кастомный UUID, который передаётся через $arFields события OnBeforeCatalogImport1C.

Анализ лога: как найти самый долгий шаг

После одного-двух импортов в файле накопится несколько тысяч строк, глазами искать узкое место бессмысленно. Мы написали простой скрипт, который парсит лог и выводит топ-10 самых медленных операций. Он группирует события по типу (сессия, элемент, раздел) и считает разницу между _START и _END. Если какой-то шаг стабильно занимает больше 5 секунд, это кандидат на оптимизацию.

PHP
// parse_log.php
$logFile = $_SERVER['DOCUMENT_ROOT'] . '/upload/import_time.log';
$lines = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

$events = [];
foreach ($lines as $line) {
    if (preg_match('/^(\S+ \S+) (\S+) (\S+) (.+)$/', $line, $m)) {
        $events[$m[2]][] = ['time' => (float)$m[3], 'id' => $m[4]];
    }
}

$durations = [];
foreach ($events as $type => $entries) {
    $startKey = $type . '_START';
    $endKey = $type . '_END';
    if (!isset($events[$startKey]) || !isset($events[$endKey])) continue;

    foreach ($events[$startKey] as $i => $start) {
        $end = $events[$endKey][$i] ?? null;
        if ($end) {
            $durations[] = [
                'type' => $type,
                'id' => $start['id'],
                'duration' => $end['time'] - $start['time']
            ];
        }
    }
}

usort($durations, fn($a, $b) => $b['duration'] <=> $a['duration']);
echo "Топ-10 самых долгих шагов:\n";
foreach (array_slice($durations, 0, 10) as $item) {
    printf("%s ID=%s — %.4f сек\n", $item['type'], $item['id'], $item['duration']);
}

5 причин, почему тормозит обмен 1С с Битрикс

Самый частый запрос на эту тему прилетает от техлидов, когда импорт из 1С уже в продакшене, а каталог разросся до 20-50 тысяч позиций. Клиенты жалуются, что товары на сайте обновляются часами, а менеджеры не могут работать с заказами, потому что сайт «лежит» во время очередного обмена. В нашей практике мы выделили пять основных причин, которые встречаются в 90% проектов с тормозами. Некоторые из них заложены в архитектуре самого модуля обмена, но большинство — это следствие кастомных доработок, которые не учитывают пакетный режим работы импорта.

  • Тяжёлые обработчики событий — кастомный код в OnAfterIBlockElementUpdate или OnBeforeCatalogImport1C, который выполняется для каждого товара по отдельности
  • Отсутствие индексов в БД, запросы к полям XML_ID, IBLOCK_ID и внешним кодам без индексов дают fullscan на каждой итерации
  • Избыточные транзакции, оборачивание каждого элемента в отдельную START TRANSACTION вместо одной транзакции на партию
  • Сброс кеша на каждый товар, вызов ClearByTag или CIBlock::ClearCache после обновления каждой единицы
  • Неоптимальные запросы в кастомном коде, выборка связанных сущностей через GetList с ORDER BY RAND или без фильтрации по IBLOCK_ID

Тяжёлые обработчики событий, это первое, что мы проверяем в проектах с тормозами. Типичный сценарий: на событие OnAfterIBlockElementUpdate повешен код, который для каждого товара пересчитывает цены по сложной формуле, подтягивает остатки со склада через веб-сервис и перегенерирует SEO-поля. В режиме ручного редактирования товара это незаметно, одна операция за 0.3 секунды. Но при импорте 50 000 позиций из 1С эти 0.3 секунды превращаются в 4+ часа чистой работы. Решение, выносить тяжёлые операции из событий в отдельный агент, который запускается после завершения импорта, либо проверять внутри обработчика флаг isImport через $GLOBALS['CACHE_MANAGER']->SetTag и пропускать логику для пакетного режима.

Отсутствие индексов в БД, проблема, которая растёт с размером каталога. Модуль обмена ищет элементы по XML_ID и IBLOCK_ID при каждой вставке или обновлении. Если на таблице b_iblock_element нет составного индекса по (IBLOCK_ID, XML_ID), MySQL делает полный проход по таблице, для 100 000 элементов это 100 000 полных сканирований за один импорт. Проверяем через EXPLAIN SELECT на запросах, которые генерирует модуль обмена, и добавляем недостающие индексы. В Bitrix Main 24.x индексы по XML_ID создаются автоматически только при установке модуля торгового каталога, если модуль ставился поверх уже существующей БД, индексы могут отсутствовать.

Избыточные транзакции, классическая ошибка в кастомном коде. Разработчики оборачивают каждое обновление элемента в START TRANSACTION и COMMIT, думая, что это повышает надёжность. На практике каждая транзакция, это накладные расходы на логирование, блокировки таблиц и синхронизацию. Правильный подход, одна транзакция на всю партию импорта (обычно 100-500 товаров), а если код выполняется внутри штатного импорта 1С, транзакция уже открыта модулем, и второй вызов START TRANSACTION её не создаёт, а увеличивает глубину вложенности, что может привести к deadlock'ам при параллельных запросах.

Сброс кеша на каждый товар, вторая по частоте причина после обработчиков. Вызов CIBlock::ClearCache($IBLOCK_ID) или $GLOBALS['CACHE_MANAGER']->ClearByTag('iblock_id_' . $IBLOCK_ID) после каждого Update элемента заставляет систему перестраивать кеш для всего инфоблока. При 50 000 товаров, 50 000 полных сбросов кеша, каждый из которых может занимать 0.5-2 секунды в зависимости от объёма закешированных данных. Решаем через флаг $GLOBALS['CACHE_MANAGER']->SetTag в начале импорта и один вызов ClearByTag после завершения всей партии, или отключаем кеш для инфоблока на время импорта через Bitrix\Main\Data\Cache::setEngine.

Неоптимальные запросы в кастомном коде, самая коварная причина, потому что она проявляется не сразу. Разработчик пишет запрос к связанным свойствам через CIBlockElement::GetList с ['IBLOCK_ID' => false] или без фильтрации по типу инфоблока. На каталоге в 5 000 элементов такой запрос отрабатывает за 0.1 секунды, незаметно. На 100 000 элементах, уже 3-5 секунд на один вызов. Если такой запрос стоит внутри обработчика OnAfterIBlockElementUpdate, который вызывается для каждого товара, получаем 3-5 секунд × 50 000 = 40+ часов дополнительного времени. Профилируем через Bitrix\Main\Diag\Debug::startTimeLabel прямо в коде обработчика и смотрим, какие запросы занимают больше всего времени.

Оптимизация обмена 1С: пошаговый план

Распространённая ошибка — пытаться оптимизировать всё сразу, переписывая архитектуру импорта «с нуля». В нашей практике это обычно приводит к долгому простою и неочевидным регрессиям. Мы действуем иначе: после замера (как мы делали в секции выше) начинаем с быстрых побед — отключения очевидных тормозов, и только потом переходим к глубоким изменениям, если они нужны. Такой план позволяет получить прирост скорости уже через час работы, а не через неделю. Ниже, пять шагов, которые мы применяем в проектах с каталогами от 20 тысяч SKU.

  1. Отключить все кастомные обработчики и проверить скорость.
    Первое, что мы делаем, временно отключаем все пользовательские обработчики событий обмена (OnBeforeCatalogImport1C, OnAfterCatalogImport1C и т.д.) в init.php и module.php. Запускаем импорт заново. Если скорость выросла в разы, проблема в одном из обработчиков. Дальше включаем их по одному и замеряем, какой именно даёт тормоз. Это занимает 15 минут, а результат очевиден.
  2. Включить пакетную обработку в настройках модуля торгового каталога.
    В админке: Настройки → Настройки продукта → Модули → Торговый каталог. Параметр «Количество элементов, выгружаемых за один шаг» (обычно стоит 1). Мы ставим 10–20 для каталогов до 30 тысяч товаров и 50–100 для более крупных. Это снижает количество HTTP-запросов между 1С и сайтом, сокращая общее время обмена в 2–3 раза без единой строки кода.
  3. Оптимизировать индексы БД.
    Стандартный импорт активно использует поля XML_ID и IBLOCK_ID. Без индексов на этих полях MySQL выполняет полный скан таблицы на каждый товар. Мы проверяем и добавляем (если их нет):
    • CREATE INDEX idx_b_iblock_element_xml_id ON b_iblock_element (XML_ID, IBLOCK_ID);
    • CREATE INDEX idx_b_catalog_product_xml_id ON b_catalog_product (XML_ID);
    • CREATE INDEX idx_b_catalog_price_xml_id ON b_catalog_price (PRODUCT_ID, CATALOG_GROUP_ID);
    Это особенно важно, если каталог > 15 тысяч элементов, без индексов запросы на поиск по XML_ID могут занимать секунды.
  4. Переписать тяжелые обработчики с использованием кеширования и отложенных операций.
    Если после шага 1 обнаружился «тяжёлый» обработчик, например, дозаполнение SEO-полей или пересчёт скидок на каждый импортированный товар, мы не удаляем его, а рефакторим. Ключевые приёмы: кеширование результатов запросов к API (например, цен конкурентов) на время сессии импорта через CCacheManager, и перенос ресурсоёмких операций (генерация мета-тегов, microdata) в агенты, которые выполняются после завершения импорта. Это снижает нагрузку на каждый элемент в 5–10 раз.
  5. Настроить агенты для фоновой обработки.
    Пересчёт остатков, генерация цен для торговых предложений, обновление поискового индекса, всё это можно вынести в фоновые агенты. В настройках модуля «Торговый каталог» есть параметр «Использовать агенты для пересчёта остатков», включаем его. Если кастомные обработчики требуют пересчёта, регистрируем агент с задержкой 1–2 минуты после завершения импорта. Так основной поток обмена не ждёт завершения этих задач.

Профилирование обмена 1С: инструменты и методы

Диагностика «на глаз» в проектах с активным обменом из 1С обычно заканчивается тем, что мы тратим неделю на переписывание не того участка кода. По нашему опыту, прежде чем что-то оптимизировать, нужно точно знать, где именно теряются секунды — на парсинге XML, на записи в БД или на перестроении кеша. У нас в практике сложился набор инструментов, который покрывает 95% задач по профилированию: от встроенного профайлера Битрикса до кастомного логирования через события. Комбинируя их, получаем объективную картину, а не догадки.

  • Bitrix Profiler — встроенный инструмент, собирает время выполнения компонентов, запросов к БД и вызовов API. Включается через admin/settings.php?mid=main&tabControl_active_tab=edit5.
  • Xdebug + Webgrind, классический профайлер PHP, показывает полный стек вызовов и время в каждой функции. Даёт «рентгеновский снимок» всего скрипта.
  • Slow query log MySQL, лог всех медленных запросов к БД. Помогает найти проблемные SELECT без индексов или тяжёлые UPDATE в цикле.
  • Кастомное логирование через события, точечные замеры времени в обработчиках OnBeforeCatalogImport1C и OnAfterCatalogImport1C. Позволяет профилировать именно логику импорта без лишнего шума.

Настраивать каждый инструмент нужно с учётом контекста. Bitrix Profiler включается в админке: заходим в «Настройки» → «Производительность» → «Панель производительности», ставим галочку «Включить профайлер». После импорта смотрим вкладку «Битрикс», там список компонентов с временем выполнения. Если видим catalog.import.1c с 30 секундами, а остальные по 0.1, проблема внутри компонента. Xdebug настраивается в php.ini: xdebug.mode=profile и xdebug.output_dir=/tmp. После импорта открываем сгенерированный cachegrind.out в Webgrind, ищем функции с наибольшим «собственным временем». Часто это CIBlockElement::SetPropertyValuesEx или CCacheManager::CleanDir. Slow query log включается в MySQL: SET GLOBAL slow_query_log = 'ON' и SET GLOBAL long_query_time = 1. После импорта смотрим лог, если десятки запросов к b_iblock_element_property без индекса по IBLOCK_ELEMENT_ID, это объясняет тормоза. Кастомное логирование делаем через AddEventHandler, на старте импорта записываем microtime(true) в переменную, на финише вычисляем разницу и пишем в syslog или CEventLog.

Узкое место обмена 1С: как найти и устранить

Самый частый запрос, который прилетает к нам от техлидов на проектах с активным обменом, звучит так: «Импорт из 1С работает, но медленно. Где копать?». Диагностика «на глаз» здесь не работает — можно неделями переписывать модуль обмена, а проблема окажется в кривом индексе или в одном забытом обработчике. У нас в практике выработалась методика поиска узкого места: идём от общего к частному. Сначала замеряем, на каком этапе импорт тормозит сильнее всего (используя штатные события из предыдущей секции), затем сужаем круг до конкретного запроса в базу или до обработчика, который съедает 80% времени. Ниже — два инструмента, которые мы используем в каждом проекте с каталогом от 20 тысяч SKU.

Проверка базы данных: медленные запросы и индексы

Когда мы видим, что импорт тормозит на этапе записи элементов или свойств, первым делом смотрим в сторону базы данных. Типичная картина: CIBlockElement::SetPropertyValuesEx вызывается в цикле, и каждый вызов порождает тяжелый SELECT или UPDATE без индекса. В MySQL для этого есть встроенный механизм, slow query log. Включаем его на время импорта, собираем все запросы, которые выполнялись дольше, скажем, 0.5 секунды, и смотрим, какие таблицы страдают чаще всего.

SQL
-- Включаем логирование медленных запросов на время импорта
SET GLOBAL slow_query_log = 'ON';


SET GLOBAL long_query_time = 0.5; -- порог в секундах


SET GLOBAL log_queries_not_using_indexes = 'ON';

-- После импорта смотрим топ-10 самых медленных запросов

SELECT query_time,
       rows_examined,
       rows_sent,
       sql_text
FROM mysql.slow_log
WHERE db = 'your_bitrix_db'
ORDER BY query_time DESC
LIMIT 10;

-- Типичный проблемный запрос (пример из практики):
-- SELECT * FROM b_iblock_element_prop_s1 WHERE IBLOCK_ELEMENT_ID = N;
-- Если на IBLOCK_ELEMENT_ID нет индекса — это тормоз на пустом месте

Проверка обработчиков событий: какой хендлер самый долгий

Вторая по частоте причина, собственные обработчики на события обмена, которые мы или клиент написали в init.php. Они могут выполнять логирование в файл, обновление связанных сущностей, отправку вебхуков, и каждый из них может «вешать» импорт на минуты. Мы на всех проектах используем простой профилировщик, который замеряет время выполнения каждого обработчика в микросекундах и пишет результат в лог.

PHP
use Bitrix\Main\EventManager;
use Bitrix\Main\Diag\Debug;

// В init.php — обёртка для замера времени всех обработчиков на событие OnAfterCatalogImport1C
EventManager::getInstance()->addEventHandler(
    'catalog',
    'OnAfterCatalogImport1C',
    function () {
        // Сохраняем время старта
        $startTime = microtime(true);

        // Регистрируем shutdown-функцию, которая сработает после всех обработчиков
        register_shutdown_function(function () use ($startTime) {
                $totalTime = (microtime(true) - $startTime) * 1000; // в миллисекундах
                $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5);
                $handlerInfo = '';

                // Извлекаем имя файла и строку, где зарегистрирован обработчик
                foreach ($backtrace as $frame) {
                    if (isset($frame['file']) && strpos($frame['file'], '/bitrix/') === false) {
                        $handlerInfo = $frame['file'] . ':' . $frame['line'];
                        break;
                    }
                }

                Debug::writeToFile(
                    [
                        'handler' => $handlerInfo ?: 'unknown',
                        'time_ms' => round($totalTime, 2),
                        'memory_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
                    ],
                    'OnAfterCatalogImport1C profile',
                    '/local/logs/import_profile.log'
                );
        });
    }
);

Ключевое в этом коде, мы не просто выводим время, а связываем его с конкретным файлом и строкой, где зарегистрирован обработчик. Это позволяет сразу понять, какой из десяти хендлеров в init.php виноват в тормозах. В логе мы видим не абстрактные цифры, а пару «файл:строка → 1234.56 мс». Дальше остаётся открыть этот файл и смотреть, что внутри: может быть, там запрос к GetList без фильтра или вызов внешнего API без таймаута.

Обратите внимание: мы используем register_shutdown_function, а не оборачиваем каждый вызов. Это даёт общее время на все обработчики, привязанные к одному событию, что обычно и нужно. Если вы хотите профилировать каждый хендлер по отдельности, придётся оборачивать их вручную или кешировать callback'и, но на практике суммарное время одного события даёт достаточно информации для первого диагноза.

События обмена 1С Битрикс: какие бывают и как использовать

Из практики: на проекте с каталогом в 40 тысяч SKU мы полгода гадали, почему после ночного импорта из 1С у части товаров слетают цены, а у другой части — остаются. Оказалось, что какой-то обработчик, повешенный на OnBeforeIBlockElementUpdate, перетирал CATALOG_PRICE для товаров, у которых в XML не было ценовой секции. Проблема решилась, когда мы разобрались, в какой последовательности стреляют события модуля торгового каталога и какие аргументы каждое из них получает. Если у вас активный обмен с 1С и вы пишете кастомную логику на импорт — знание этих событий превращает «магию слетающих полей» в предсказуемый конвейер.

Событие Момент вызова Аргументы Отменяемо
OnBeforeCatalogImport1C До начала сессии импорта $arParams Да
OnStartCatalogImport1C После авторизации, перед обработкой XML $arParams Нет
OnSuccessCatalogImport1C После успешного завершения всей сессии $arParams, $arResult Нет
OnBeforeIBlockElementUpdate Перед обновлением каждого элемента &$arFields Да
OnAfterIBlockElementUpdate После обновления элемента &$arFields Нет

Типовые задачи решаются конкретными событиями. Когда нужно дозаполнить поля, которые 1С не передаёт (SEO-тексты, OG-метки, пользовательские свойства), мы вешаемся на OnBeforeIBlockElementUpdate и модифицируем $arFields до записи в базу. Для валидации, например, чтобы не пропустить товар с нулевым артикулом, используем OnBeforeCatalogImport1C с возвратом false для прерывания всей сессии, или OnBeforeIBlockElementUpdate с return false для пропуска конкретного элемента. Если задача, логирование (записать в отдельную таблицу, сколько времени ушло на каждый товар), выбираем OnAfterIBlockElementUpdate: он срабатывает уже после записи, не блокирует импорт и получает финальные $arFields с ID элемента. По нашему опыту, комбинация OnBeforeIBlockElementUpdate + OnAfterIBlockElementUpdate покрывает 80% нестандартных доработок обмена, от подстановки шаблонов до аудита изменений.

Как ускорить обмен 1С Битрикс: чек-лист

Когда мы уже замерили время, нашли узкие места и применили точечные оптимизации из предыдущих разделов, остаётся последний шаг — собрать все решения в единый план внедрения. В нашей практике именно системный подход даёт стабильный прирост скорости, а не разовые «заплатки». Ниже — чек-лист из десяти пунктов, от самых простых до глубоких архитектурных изменений. Проходите последовательно, не перескакивая через этапы.

  • Включите асинхронный режим импорта в настройках модуля «1С-Битрикс: Управление сайтом», это разгрузит HTTP-воркер.
  • Увеличьте max_execution_time и memory_limit на сервере до 600 секунд и 512 МБ соответственно, обрыв импорта на середине съедает больше времени, чем запас.
  • Отключите поисковую переиндексацию во время импорта через COption::SetOptionString('search', 'reindex_immediate', 'N'), запустите её крон-задачей после.
  • Удалите или оптимизируйте обработчики на событиях OnAfterIBlockElementUpdate и OnAfterIBlockElementAdd, именно они чаще всего генерируют лишние SQL-запросы.
  • Переключите обновление цен и остатков на прямые SQL-запросы через CCatalogProduct::Update в цикле без повторной загрузки элемента.
  • Выключите автоматическое создание ЧПУ для новых товаров, генерируйте их через CIBlockSection::GetList и CUtil::translit только для изменённых позиций.
  • Замените CIBlockElement::SetPropertyValuesEx на массовую запись через CIBlockProperty::GetList + один UPDATE, это сокращает число запросов с N до 1.
  • Включите кэширование результатов выборок внутри цикла импорта через CCacheManager::GetCache, повторные запросы к одним и тем же элементам не должны долбить базу.
  • Разделите импорт товаров и торговых предложений на два отдельных запроса из 1С, обрабатывайте их последовательно, а не вперемешку.
  • Перепишите собственный обработчик OnAfterCatalogImport1C на асинхронное выполнение через агентов, тяжёлую пост-обработку (генерацию карт сайта, микроразметку) выносите за пределы сессии импорта.
#Bitrix #PHP #SQL #MySQL
А
автор · Backend / SRE Engineer
Артем Колячек

Backend-разработчик и SRE в студии Paradigma. Занимается тем, что у других проектов обычно обнаруживается за неделю до запуска: переездом Bitrix-проектов между серверами, починкой кешей после миграций, выстраиванием pipeline для контейнеров, мониторингом под нагрузкой.

До Paradigma — 7 лет в backend (PHP + Postgres) и в operations (Linux, Docker, Coolify, restic-бэкапы). Любит когда логи разговаривают полным синтаксисом ошибки, а не «что-то пошло не так».

На блоге пишет ровно про те ситуации с которыми сам разбирался руками: какой Bitrix-апдейт сломал кеш и как откатить, почему Docker-сеть не находит контейнер после рекрейта, что делать когда asyncpg ругается на event loop.