Optimizing the import of large volumes of 1C-Bitrix data

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Optimization of large data import 1C-Bitrix

Standard 1C exchange via CommerceML processes 50,000 items in 4 hours. For a catalog of 200,000 items with 30 properties and 5 price types — exchange doesn't complete: hits max_execution_time, exhausts memory, or locks tables for hours. Import optimization — work at three levels: PHP and DB tuning, exchange procedure enhancement, and transition to incremental import.

Why standard exchange is slow

CommerceML exchange works this way: 1C exports full XML file (import.xml + offers.xml), Bitrix parses it and for each element calls CIBlockElement::Add() or CIBlockElement::Update(). Each call:

  1. Checks access rights
  2. Calls OnBefore* event handlers
  3. Writes element to b_iblock_element
  4. Writes properties to b_iblock_element_property (separate INSERT/UPDATE for each property)
  5. Writes prices to b_catalog_price
  6. Updates search index
  7. Invalidates cache
  8. Calls OnAfter* event handlers

Per element — 10–20 SQL queries. For 200,000 elements — 2–4 million queries. Plus facet index recreation on each change.

PHP tuning

Parameter Value for import Default
max_execution_time 0 (unlimited) 30
memory_limit 2048M 128M
post_max_size 200M 8M
upload_max_filesize 200M 2M

These parameters set globally in php.ini or for specific exchange script via .htaccess or virtual host. For PHP-FPM — separate pool with increased limits for /bitrix/admin/1c_exchange.php.

MySQL tuning

During import:

  • Disable sync_binlog (if not using replication) — each INSERT won't be synced to disk: SET GLOBAL sync_binlog = 0;
  • Increase innodb_log_file_size to 1–2 GB — reduces checkpoint frequency and speeds writes
  • innodb_flush_log_at_trx_commit = 2 — transaction log written once per second instead of per transaction
  • innodb_autoinc_lock_mode = 2 — speeds bulk INSERT (interleaved lock)

After import revert settings to production values. For automation — wrapper script changing parameters before import and reverting after.

Disabling handlers and indexes

Main speedup — disable unnecessary work during import:

  • Event handlers. If OnAfterIBlockElementUpdate sends notifications or updates external system — on 200,000 items this is 200,000 HTTP requests. Disable via flag: check defined('CATALOG_IMPORT_RUNNING') in handler.
  • Search index. Disable search module during import: \Bitrix\Main\ModuleManager::deActivate('search') — radical but effective. Alternative — disable catalog infoblock indexing in search module settings.
  • Faceted index. Recreate on each item update — useless on mass import. Disable auto-update, after import recreate once.
  • URL transliteration and slug generation. If CODE generated on element save — extra computations. Pass CODE from 1C or generate batch after import.

Batch import via D7 API

Instead of element-by-element CIBlockElement::Update() — direct table work via D7 ORM:

// Batch price update
$connection = Application::getConnection();
$connection->queryExecute("
    INSERT INTO b_catalog_price (PRODUCT_ID, CATALOG_GROUP_ID, PRICE, CURRENCY)
    VALUES (1, 1, 100.00, 'RUB'), (2, 1, 200.00, 'RUB'), ...
    ON DUPLICATE KEY UPDATE PRICE = VALUES(PRICE), CURRENCY = VALUES(CURRENCY)
");

INSERT ... ON DUPLICATE KEY UPDATE batches 1000 rows in one query instead of 1000 separate UPDATEs. Speedup — 10–50x.

Limitation: direct table writes don't trigger event handlers, don't invalidate cache, don't update facet index. All must be done manually after import.

Incremental import

Full import of 200,000 items nightly — wasteful if only 500 changed. Incremental approach:

  1. On 1C side — export only changed elements (by modification date)
  2. On Bitrix side — accept delta via REST API or custom endpoint
  3. Hash comparison — store MD5 of key fields for each item. On import compare hash — if unchanged, skip

For exchanges more than once per hour incremental import is the only viable option.

Monitoring and diagnostics

  • Import log — Bitrix writes to /bitrix/catalog_export/. Analyze timing of each step.
  • Slow query log — enable on MySQL during import (long_query_time = 1). Shows problematic queries.
  • ProfilingBitrix\Main\Diag\SqlTracker counts SQL query qty and time. Enable on test run, find bottlenecks.

Optimization timeline

Task Effect Duration
PHP + MySQL tuning + disable handlers 2–5x speedup 1–2 days
Batch import via direct SQL 10–50x speedup 3–5 days
Incremental import (delta + hashes) Import in minutes instead of hours 1–1.5 weeks
Full complex (all three levels + monitoring) 200K+ catalog works normally 1.5–2 weeks

Key principle: standard CommerceML exchange is development convenience at cost of performance. For catalogs over 50,000 items need to consciously decide where standard mechanism is acceptable and where — direct SQL and incremental logic.