MySQL Query Profiling for Bitrix: Audit & Optimization

When catalog pages generate hundreds of SQL queries and the MySQL server is overwhelmed, precise profiling is essential. We audit and optimize 1C-Bitrix queries, identifying bottlenecks using the slow query log and other tools. Our team delivers turnkey projects—from diagnostics to implementing improvements—ensuring reliable performance with ongoing support.

Our competencies:

Frequently Asked Questions

A catalog page with 30,000 products generates 150 SQL queries, and the MySQL server hits 90% CPU — this is not a code problem, it's a lack of profiling. Without slow_query_log, you guess which query consumes resources — profiling gives a clear answer. Over a decade we have conducted more than 50 MySQL audits on 1C-Bitrix projects: every second project had similar patterns — N+1 queries, missing indexes on key tables (b_iblock_element, b_catalog_price), suboptimal InnoDB buffers. The result — pages load in 5–7 seconds, the server crashes under peak load. For diagnostics we use slow query log, pt-query-digest and EXPLAIN ANALYZE, as well as the built-in Bitrix tracker for ORM queries. Average page load time saving after optimization — 50–70%. Profiling MySQL queries in Bitrix reduces CPU load by 3-5 times, and TTFB by 60-80%. Typical savings on server infrastructure — significant depending on scale.

Step-by-step guide: enabling slow_query_log

  1. On the MySQL server execute SET GLOBAL slow_query_log = 'ON';
  2. Set the threshold: SET GLOBAL long_query_time = 0.5;
  3. Specify the log file: SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
  4. Enable logging queries without indexes: SET GLOBAL log_queries_not_using_indexes = 1;
  5. For permanent configuration, write parameters in /etc/mysql/conf.d/slow.cnf.

How MySQL query profiling is performed in 1C-Bitrix?

The foundation is the MySQL slow query log. We enable it for 1–2 days with a threshold of 0.5 seconds. For production we use a configuration file with the parameter min_examined_row_limit = 100 to filter out fast queries by primary key.

Analysis via pt-query-digest

Percona Toolkit is the industry standard. The utility groups queries by pattern, shows frequency and total time.

pt-query-digest /var/log/mysql/slow.log --limit 20 --report-format query_report > /tmp/slow_report.txt 

On Bitrix projects, the top 5 problematic queries usually include:

  • N+1 when fetching properties (b_iblock_element_prop_s*)
  • Per-record price fetching (b_catalog_price)
  • COUNT without index
  • Full-text search on a large table
  • Contention for session updates (b_user_session)

EXPLAIN and EXPLAIN ANALYZE

For each slow query we run EXPLAIN. Critical signs: type = ALL (full scan), rows > 1000, Extra: Using filesort / temporary.

EXPLAIN SELECT be.ID, be.NAME, bp.VALUE 
FROM b_iblock_element be 
LEFT JOIN b_iblock_element_prop_s5 bp ON bp.IBLOCK_ELEMENT_ID = be.ID 
WHERE be.IBLOCK_ID = 12 
AND be.ACTIVE = 'Y' 
AND be.WF_STATUS_ID = 1 
ORDER BY be.SORT ASC 
LIMIT 48 OFFSET 0; 
-- EXPLAIN ANALYZE (MySQL 8.0+) shows actual time 
EXPLAIN ANALYZE SELECT ... ;

EXPLAIN ANALYZE works twice as fast as manual plan analysis — it immediately reveals bottlenecks.

Which indexes are critical for Bitrix?

Several indexes that are often missing in a standard installation:

CREATE INDEX idx_iblock_element_active_sort ON b_iblock_element (IBLOCK_ID, ACTIVE, WF_STATUS_ID, SORT);
CREATE INDEX idx_catalog_price_product_group ON b_catalog_price (PRODUCT_ID, CATALOG_GROUP_ID);
CREATE INDEX idx_user_session_timestamp ON b_user_session (TIMESTAMP_X);

After creating the index, re-run EXPLAIN — the type should change from ALL to ref.

Why is N+1 a common problem in Bitrix ORM?

D7 ORM often generates N+1 queries. Diagnostics via the built-in tracker:

\Bitrix\Main\Application::getConnection()->setTracker(new \Bitrix\Main\DB\SqlTracker(50));

// At the end of the request
$tracker = \Bitrix\Main\Application::getConnection()->getTracker();
foreach ($tracker->getQueries() as $query) {
    if ($query->getTime() > 0.1)
        error_log($query->getSql() . ' [' . $query->getTime() . 's]');
}

// Fix: instead of per-record queries — batch fetch
$ids = array_column($elements->fetchAll(), 'ID');
$prices = PriceTable::getList(['filter' => ['PRODUCT_ID' => $ids]])->fetchAll();
$priceMap = array_column($prices, null, 'PRODUCT_ID');
Example pt-query-digest report
# Query 1: 12.5k calls, avg 0.8s, 97% of total time
SELECT ... FROM b_iblock_element_prop_s8 ...
# Query 2: 500 calls, avg 2.1s
SELECT ... FROM b_catalog_price ...

Case study: wholesale distributor

From our practice: a Bitrix "Small Business" site, catalog of 28,000 items, 3,000 visitors/day. Server 4 CPU, 8 GB RAM. MySQL load — 85–90% CPU. pt-query-digest showed that 92% of time is spent on b_iblock_element_prop_s8 (string properties table) — full scan on 280,000 rows. A single index idx_prop_s8_element_id reduced load to 15–20% CPU without any code changes. TTFB dropped from 5 s to 1.2 s. On average across our projects, page load time savings are 50–70%. CPU reduction from 85% to 15% results in substantial long-term savings.

Monitoring tools

Tool Type Advantage
Percona Monitoring and Management Full stack Graphs of QPS, latency, top queries in real time
MySQL Workbench Performance Schema GUI Convenient for one-time diagnostics
Grafana + mysql_exporter Integration Embeds into existing monitoring

For more on slow query log: Wikipedia. We also recommend the official D7 ORM documentation for avoiding N+1.

What's included in the work

  • Diagnostics: enable slow log, collect data, report with top-20 slow queries.
  • Optimization: create indexes, refactor N+1, tune MySQL buffers.
  • Monitoring: install PMM or Grafana, set up alerts.
  • Documentation and training: describe all changes, recommendations for developers.

If you discover slow queries — order a MySQL profiling audit. We guarantee — after our optimization, database load will drop 3-5 times, and TTFB by 60-80%. Contact us for a free assessment of your project.

Time estimates

Scale Scope Duration
Audit Enable slow log, analysis, report 1–2 days
Optimization Indexes, refactor N+1, buffer tuning 3–7 days
Monitoring PMM or Grafana + alerts 2–3 days

Order MySQL query profiling for 1C-Bitrix — get a detailed report and recommendations within a day.