Performance Optimization for 1C-Bitrix Websites
b_iblock_element_property — the table behind 80% of performance issues on Bitrix projects. EAV structure: one row per value per property per element. A catalog of 50,000 products with 30 properties — one and a half million rows. The smart filter JOINs this table with b_iblock_element across five properties — and MySQL goes into a full table scan for 3-5 seconds. Bitrix optimization starts with this table and radiates across the entire infrastructure.
Server-Side Optimization
Nginx. Not just "enabled gzip." Specifically:
-
gzip_comp_level 4-5— higher is pointless, CPU consumes more than it saves in bandwidth -
brotli onwithbrotli_static on— for pre-compressed files - HTTP/2 with
http2_max_concurrent_streams 128 -
fastcgi_cachefor PHP responses — caching at the Nginx level, bypassing PHP-FPM entirely -
worker_processes auto,worker_connectionstuned to actual concurrent connections
PHP-FPM. The choice between pm = dynamic and pm = static is not academic:
- Static: fixed number of workers, no fork overhead. For dedicated servers with predictable load
- Dynamic: saves RAM during low traffic.
pm.max_childrencalculated as(available RAM - RAM for MySQL/Redis) / average memory per process - OPcache:
opcache.memory_consumption=256,opcache.max_accelerated_files=20000,opcache.validate_timestamps=0in production (PHP-FPM restart on deploy)
MySQL/MariaDB. Almost always the main bottleneck:
-
slow_query_logwith a 0.5 sec threshold. Every query analyzed viaEXPLAIN -
innodb_buffer_pool_size= 70-80% of available RAM on a dedicated server -
query_cache_type = 0on MySQL 8.x (query cache removed) or MariaDB withquery_cache_sizetuned to load profile - Composite indexes for faceted search:
(IBLOCK_ID, IBLOCK_PROPERTY_ID, VALUE)onb_iblock_element_property -
OPTIMIZE TABLE b_iblock_element_propertyafter bulk operations
Caching: Three Levels
Managed component cache. TTL configured individually per component. Catalog — 3600 sec, news feed — 300 sec, banners — 86400. Identical TTL everywhere guarantees either stale data or useless cache.
Composite cache. The "Composite Site" technology (bitrix:composite). Nginx serves ready-made HTML from a file, PHP doesn't launch. Dynamic zones (cart, authentication, regional content) are loaded via an AJAX request through CBitrixComponent::setFrameMode(true). TTFB < 50 ms. But: not all components are compatible, $APPLICATION->ShowPanel() and direct output via echo break the composite. We verify each page via the "Performance → Composite Site" panel.
Memcached / Redis. Moving cache out of the filesystem:
- Sessions → Redis (
session.save_handler = redis). 10-50x faster than file storage, plus works in a cluster - Component cache → Memcached via
.settings.php:'cache' => ['type' => 'memcache'] - ORM query cache — so identical
GetList()calls don't hit MySQL on every request
Frontend
Images — 60-80% of page weight:
- WebP via
CFile::ResizeImageGet()withBX_RESIZE_IMAGE_PROPORTIONAL+ conversion -
srcset+sizes— don't load a 3000px image into a 400px block -
loading="lazy"for everything below the fold - AVIF for browsers that support it — another 20-30% savings vs WebP
CSS/JS:
- Built-in Bitrix module: bundling and minification via "Settings → CSS/JS Optimization"
- PurgeCSS / UnCSS — on a typical Bitrix project, 60-70% of CSS is unused (styles from all connected components are pulled in)
-
defer/asyncfor non-critical JS - Critical CSS inlined in
<head>for instant FCP
Fonts:
-
<link rel="preload" as="font" crossorigin>for the primary font -
font-display: swap— text is visible immediately, font loads in the background - Subsetting via
pyftsubset— extract Cyrillic + Latin, everything else is unnecessary. File size reduced 3-5x
CDN
- Cloudflare, BunnyCDN, AWS CloudFront, or Russian providers (Selectel CDN, VK Cloud CDN)
- Static assets (CSS, JS, images, fonts) — via CDN
- Cache rules:
Cache-Control: public, max-age=31536000, immutablefor files with a hash in the name -
imgproxyor Cloudflare Polish — on-the-fly image optimization without loading the origin
Load Testing
Not synthetic benchmarks, but real scenarios:
- k6 / wrk — simulating routes: catalog → filtering → product card → cart → checkout
- Metrics: RPS, response time (p50, p95, p99), error rate
-
Xdebug (callgrind) or Blackfire — PHP profiling, finding specific bottlenecks. We see that
CIBlockElement::GetList()with fivePROPERTY_*filters takes 2 sec — we optimize exactly that call
Database Optimization: Beyond Standard Settings
Indexes. Composite indexes for faceted search. Covering indexes for frequent queries — MySQL responds from the index without touching data. Partial indexes (MariaDB) for filtering by ACTIVE = 'Y'. Audit of unused indexes — each one slows down INSERT/UPDATE.
Partitioning. For tables with millions of rows: b_stat_session, b_search_content_stem, Highload blocks with history. Partitioning by date — a query for "orders this month" doesn't scan three years of data.
Cleanup. Every Bitrix database accumulates over a year or two: stale search index in b_search_content, expired records in b_cache_tag, b_iblock_element_prop_s* history spanning years, gigabytes of logs in b_event_log. We set up regular cleanup via agents.
Results
| Metric | Before | After |
|---|---|---|
| TTFB | 800-2000 ms | 50-200 ms |
| Full page load | 4-8 sec | 1.5-2.5 sec |
| PageSpeed (mobile) | 30-50 | 80-95 |
| Concurrent users | 50-100 | 500-2000+ |
Monitoring
Without monitoring, everything degrades within six months. A new module, uncleaned logs, a template change — and speed returns to its original state.
- web-vitals API — Real User Monitoring from actual visitors
- Synthetic monitoring — Pingdom, UptimeRobot, regular checks from multiple locations
- Alerts — TTFB > 500 ms or LCP > 3 sec → notification
Hosting
| Type | Best For | Limitations |
|---|---|---|
| Shared | Landing pages, up to 500 visits/day | No control over PHP-FPM, Redis, Nginx |
| VPS/VDS | Most projects | Up to 30K visits/day with proper configuration |
| Dedicated | Large stores | Full control, NVMe, plenty of RAM |
| Cloud (Yandex Cloud, VK Cloud, AWS) | Uneven load | Auto-scaling during sales, fault tolerance |
Pricing
| Type of Work | Timeline | Cost |
|---|---|---|
| Basic optimization (cache, images, minification) | 2-3 days | from 25,000 RUB |
| Database optimization (indexes, slow queries, tuning) | 3-5 days | from 40,000 RUB |
| Server infrastructure (Nginx, PHP-FPM, Redis) | 2-3 days | from 30,000 RUB |
| Comprehensive (server + DB + frontend + CDN) | 1-3 weeks | from 80,000 RUB |
| Load testing and profiling | 2-3 days | from 20,000 RUB |
| Cluster architecture (load balancing, replication) | 1-2 weeks | from 120,000 RUB |
Reducing TTFB by 1 second yields approximately +7% to conversion. For a store with 5M/month revenue — that's 350K in additional monthly revenue.







