Optimizing 1C and 1C-Bitrix Exchange Performance
An exchange with 50,000 products taking 4 hours and grinding the entire site to a halt during business hours is not normal — it is a symptom. The typical cause: the exchange was configured long ago for 5,000 products, the catalog grew tenfold, and the settings were never revisited. Exchange optimization is a complex effort on both sides of the integration.
Profiling: Finding the Bottleneck
Before optimizing anything — measure. Add timestamps to the exchange log:
// In the OnIBlockElementImport handler
$timings[] = [
'step' => 'element_import',
'element' => $elementXmlId,
'time' => microtime(true) - $startTime,
];
After the exchange, analyze where 80% of the time is spent. Common culprits:
- XML parsing — files are too large, not split into chunks
- Database writes — indexes, triggers, unoptimized INSERTs
- Price recalculation — if automatic price rule recalculation is enabled
- Search indexing — rebuilding the search index on every change
Optimizing XML Parsing
Split the export into batches. In 1C settings, set "Number of elements per file" = 1000–2000. Each file is processed by a separate HTTP request. 1C-Bitrix processes a file in 30–60 seconds instead of hanging for 2+ hours.
Enable ZIP compression. A file with 2,000 products uncompressed is 8–15 MB; compressed it is 1–3 MB. This matters significantly for the channel between 1C and the hosting server, especially over a slow connection.
In 1C publication settings:
Use data compression: Yes
Compression threshold: 1024 bytes
Optimizing Database Writes
The standard 1C-Bitrix import calls CIBlockElement::Add/Update for each element — a full cycle including validation, event handlers, and cache invalidation. For 50,000 elements that means 50,000 separate transactions.
Disable unnecessary events during import:
// Before import
define('BX_BUFFER_MESS', true); // suppress email notifications
$GLOBALS['STOP_STATISTICS'] = true; // skip statistics updates
define('NO_AGENT_STATISTIC', true);
Deferred re-indexing. Search is re-indexed after every element change. For bulk imports — disable auto-indexing and trigger re-indexing as a separate agent after the exchange completes:
// Temporarily disable indexing
\Bitrix\Main\Config\Option::set('search', 'indexer_auto_mode', 'N');
// After the exchange, trigger re-indexing
CSearch::ReIndexAll(true, CATALOG_IBLOCK_ID);
Deferred cache invalidation. Instead of calling BXClearCache on every element update — collect changed elements into an array and invalidate the cache in a single batch at the end of the exchange.
Optimizing Database Queries During Import
When updating an element, 1C-Bitrix performs a SELECT to check for existence, then an UPDATE or INSERT. In a bulk import, you can preload all XML_IDs into memory and avoid per-element SELECTs:
// Fetch all existing elements in a single query
$existing = [];
$res = CIBlockElement::GetList(
[],
['IBLOCK_ID' => CATALOG_IBLOCK_ID],
false,
false,
['ID', 'XML_ID']
);
while ($el = $res->Fetch()) {
$existing[$el['XML_ID']] = $el['ID'];
}
// During import: isset($existing[$xmlId]) instead of SELECT
Splitting the Exchange by Data Type
Running a full exchange (catalog + prices + stock) in a single session is wasteful. Split it into independent streams:
| Stream | Contents | Frequency | Load |
|---|---|---|---|
| Full catalog | Descriptions, properties, images | Once/night | High, overnight |
| Prices | offers*.xml with prices only |
Every hour | Low |
| Stock | offers*.xml with stock only |
Every 15 min | Minimal |
| Orders | orders.xml |
Every 15–30 min | Minimal |
In 1C, multiple independent scheduled tasks can be configured for different export types.
Caching on the 1C-Bitrix Side
Review the cache settings in the catalog module:
Settings → Product Settings → Performance:
- Catalog element cache: enable, TTL 3600 seconds
- Property cache: enable
- Trade offer cache: enable for stores with product variants
During the exchange, cache is automatically invalidated for changed elements. If invalidation takes a long time — check the cache size on disk (/bitrix/cache/iblock/) and increase memory_limit if necessary.
Case Study: Reducing Exchange Time from 4 Hours to 25 Minutes
An auto parts online store with 65,000 SKUs. The exchange ran once a day and took 4+ hours, blocking price recalculation for that entire period.
Root causes identified:
- The entire catalog in a single XML file (240 MB)
- Search re-indexed on every element
- Price recalculation against 12 rules on every price change
-
BXClearCachefor the entire infoblock every 100 elements
After optimization:
- Catalog split into files of 2,000 elements each
- Deferred re-indexing via a separate agent
- Price recalculation only after import completion, not during
- Batch cache invalidation at the end of the session
Result: full exchange — 25 minutes. Stock and price exchange only (every hour) — 3–4 minutes.
Optimization Timelines
| Task | Duration |
|---|---|
| Profiling and analysis of the current exchange | 4–8 hours |
| Batch splitting + ZIP | 2–4 hours |
| Deferred re-indexing + cache | 1 day |
| Splitting into independent streams | 1–2 days |
| Full audit + custom import with batch writes | 3–5 days |







