Профілювання MySQL-запитів 1С-Бітрікс: аудит та оптимізація
Сторінка каталогу з 30 тисячами товарів генерує 150 SQL-запитів, а сервер MySQL упирається в 90% CPU — це не проблема коду, це відсутність профілювання. Без slow_query_log ви гадаєте, який запит з'їдає ресурси — профілювання дає чітку відповідь. За десять років ми провели понад 50 аудитів MySQL на проєктах 1С-Бітрікс: кожен другий проєкт мав схожі патерни — N+1 запити, відсутність індексів на ключових таблицях (b_iblock_element, b_catalog_price), неоптимальні буфери InnoDB. Результат — сторінки вантажаться 5–7 секунд, сервер падає при пікових навантаженнях. Для діагностики ми використовуємо slow query log, pt-query-digest та EXPLAIN ANALYZE, а також вбудований трекер Бітрікс для ORM-запитів. Середня економія часу завантаження після оптимізації — 50–70%. Профілювання MySQL-запитів Бітрікс дозволяє знизити навантаження CPU в 3-5 разів, а TTFB — на 60-80%. Типова економія на серверній інфраструктурі — до $2.7k–3.9k./рік (в перерахунку на гривні близько 120 000 грн).
Покрокова інструкція: включення slow_query_log
- На сервері MySQL виконайте
SET GLOBAL slow_query_log = 'ON'; - Встановіть поріг:
SET GLOBAL long_query_time = 0.5; - Вкажіть файл логу:
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; - Увімкніть логування запитів без індексів:
SET GLOBAL log_queries_not_using_indexes = 1; - Для постійної конфігурації пропишіть параметри в
/etc/mysql/conf.d/slow.cnf.
Як виконується профілювання MySQL-запитів в 1С-Бітрікс?
Основа — slow query log MySQL. Вмикаємо його на 1–2 дні з порогом 0.5 секунди. Для production використовуємо файл конфігурації з параметром min_examined_row_limit = 100, щоб відсікти швидкі запити по первинному ключу.
Аналіз через pt-query-digest
Percona Toolkit — індустріальний стандарт. Утиліта групує запити за шаблоном, показує частоту та загальний час.
pt-query-digest /var/log/mysql/slow.log --limit 20 --report-format query_report > /tmp/slow_report.txt На Бітрікс-проєктах топ-5 проблемних запитів зазвичай містить:
- N+1 при вибірці властивостей (
b_iblock_element_prop_s*) - Поштучна вибірка цін (
b_catalog_price) - COUNT без індексу
- Повнотекстовий пошук по великій таблиці
- Конкуренція за оновлення сесій (
b_user_session)
EXPLAIN та EXPLAIN ANALYZE
Для кожного повільного запиту запускаємо EXPLAIN. Критичні ознаки: 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+) показує реальний час EXPLAIN ANALYZE SELECT ... ; EXPLAIN ANALYZE працює вдвічі швидше ручного аналізу плану — одразу видає вузькі місця.
Які індекси критичні для Бітрікс?
Декілька індексів, які часто відсутні в стандартній установці:
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); Після створення індексу перезапускаємо EXPLAIN — тип має змінитися з ALL на ref.
Чому N+1 — часта проблема в ORM Бітрікс?
D7 ORM часто генерує N+1 запитів. Діагностика через вбудований трекер:
\Bitrix\Main\Application::getConnection()->setTracker(new \Bitrix\Main\DB\SqlTracker(50)); // В кінці запиту $tracker = \Bitrix\Main\Application::getConnection()->getTracker(); foreach ($tracker->getQueries() as $query) { if ($query->getTime() > 0.1) error_log($query->getSql() . ' [' . $query->getTime() . 's]'); } // Виправлення: замість поштучних запитів — batch вибірка $ids = array_column($elements->fetchAll(), 'ID'); $prices = PriceTable::getList(['filter' => ['PRODUCT_ID' => $ids]])->fetchAll(); $priceMap = array_column($prices, null, 'PRODUCT_ID'); Приклад звіту pt-query-digest
# 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 ... Кейс: оптовий дистриб'ютор
З нашої практики: сайт на Бітрікс «Малий бізнес», каталог 28 000 позицій, 3 000 відвідувачів/день. Сервер 4 CPU, 8 GB RAM. Навантаження на MySQL — 85–90% CPU. pt-query-digest показав, що 92% часу йде на b_iblock_element_prop_s8 (таблиця строкових властивостей) — full scan на 280 000 рядків. Один індекс idx_prop_s8_element_id знизив навантаження до 15–20% CPU без жодних змін у коді. TTFB впав з 5 с до 1,2 с. В середньому за нашими проєктами економія часу завантаження становить 50–70%. Зниження CPU з 85% до 15% заощадило $1.8k–2.6k./рік (близько 80 000 грн) на серверах.
Інструменти моніторингу
| Інструмент | Тип | Перевага |
|---|---|---|
| Percona Monitoring and Management | Повний стек | Графіки QPS, latency, топ запитів у реальному часі |
| MySQL Workbench Performance Schema | GUI | Зручний для разової діагностики |
| Grafana + mysql_exporter | Інтеграція | Вбудовується в існуючий моніторинг |
Докладніше про slow query log: Wikipedia. Також рекомендуємо офіційну документацію D7 ORM для уникнення N+1.
Що входить в роботу
- Діагностика: включення slow log, збір даних, звіт з топ-20 повільних запитів.
- Оптимізація: створення індексів, рефакторинг N+1, налаштування буферів MySQL.
- Моніторинг: встановлення PMM або Grafana, налаштування алертів.
- Документація та навчання: опис всіх змін, рекомендації для розробників.
Якщо ви виявили повільні запити — замовте аудит профілювання MySQL. Гарантуємо — після нашої оптимізації навантаження на базу знизиться в 3–5 разів, а TTFB — на 60–80%. Зв'яжіться з нами для безкоштовної оцінки вашого проєкту.
Терміни
| Масштаб | Склад | Термін |
|---|---|---|
| Аудит | Включення slow log, аналіз, звіт | 1–2 дні |
| Оптимізація | Індекси, рефакторинг N+1, налаштування буферів | 3–7 днів |
| Моніторинг | PMM або Grafana + алерти | 2–3 дні |
Замовте профілювання MySQL-запитів 1С-Бітрікс — отримайте розгорнутий звіт та рекомендації протягом дня.







