Як прискорити 1С-Бітрікс: повний аудит SQL-запитів, індексів та кешування
На типовому навантаженому сайті Бітрікс генерує від 200 до 1000 SQL-запитів на сторінку. Більшість із них — повторювані, надлишкові або з SELECT *. Перш ніж купувати дорожчий сервер, варто розібратися, які саме запити гальмують і чому. За 10 років роботи з Бітрікс ми не раз бачили проєкти, де один неправильний індекс або відсутність кешу з'їдали 70% ресурсів БД. Середня економія після аудиту — значна та залежить від конкретних умов.
Оптимізація SQL-запитів — не разова дія, а регулярний процес. Наші клієнти економлять до 50% навантаження сервера та прискорюють генерацію сторінок у 2-5 разів. Окупається така оптимізація за 2-3 місяці. Давайте подивимося, як виявити вузькі місця та усунути їх.
Приклад із практики: інтернет-магазин із каталогом 50 000 товарів. Головна сторінка формувалася 12 секунд. Після профілювання виявили 15 запитів до b_iblock_element_property без індексу — у два рази швидше. Додали композитний індекс — сторінка почала завантажуватися за 0.4 с. Економія на сервері — значна.
Як виявити повільні SQL-запити: покрокова інструкція
- Увімкніть SQL-трекер Бітрікса на панелі продуктивності (
/bitrix/admin/perfmon_panel.php) або додайте програмний запис:
\Bitrix\Main\Diag\SqlTracker::getInstance()->start(); // ... ваш код ... $tracker = \Bitrix\Main\Diag\SqlTracker::getInstance(); $tracker->stop(); foreach ($tracker->getQueries() as $query) { echo $query->getSql() . ' — ' . $query->getTime() . 'ms' . PHP_EOL; } -
Проаналізуйте трекер: шукайте запити довші за 50 мс, дублі (той самий запит повторюється 10—50 разів на сторінку), запити без
WHEREпо великих таблицях. -
Додатково увімкніть
slow_query_logу MySQL/MariaDB (long_query_time = 0.5уmy.cnf) — він дає реальну картину під навантаженням у продакшені.
Чому індекси критичні для Бітрікса?
b_iblock_element може містити від 10 000 до 1 000 000 рядків. Запит SELECT * FROM b_iblock_element WHERE IBLOCK_ID = 5 AND ACTIVE = 'Y' ORDER BY SORT без індексу по (IBLOCK_ID, ACTIVE, SORT) виконує full table scan. Перевірте через EXPLAIN SELECT ... — якщо в type побачите ALL, індексу немає. Селективність індексу має бути високою — уникайте стовпців із низькою кардинальністю.
Бітрікс створює індекси при встановленні, але не для користувацьких полів (UTS-таблиці b_uts_iblock_N_single). Індекси по цих таблицях потрібно додавати вручну. За нашим досвідом, правильні індекси прискорюють конкретні запити в 2–10 разів. Детальніше про індекси БД — у статті Wikipedia: «Індекс (бази даних)».
Надлишкова вибірка полів
CIBlockElement::GetList() за замовчуванням робить LEFT JOIN з b_iblock_element_iprop і повертає десятки полів, включаючи DETAIL_TEXT вагою в мегабайти. Якщо на сторінці потрібні лише ID, NAME та PREVIEW_PICTURE — задавайте $select явно:
CIBlockElement::GetList( ['SORT' => 'ASC'], ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'], false, ['nPageSize' => 20], ['ID', 'NAME', 'PREVIEW_PICTURE'] ); Це знижує навантаження на 20–40%.
N+1 проблема та способи її усунути
Класична ситуація: завантажили 20 елементів, потім у циклі для кожного окремим запитом завантажуєте властивості. Підсумок — 21 запит замість 1–2. У старому API вирішується через $arSelectFields, у D7 — через fetchCollection() із fill(). Після оптимізації кількість запитів знижується в 3–5 разів.
Повторні запити одних і тих самих даних
Налаштування сайту, групи користувачів, розділи інфоблоків — запитуються на кожній сторінці повторно. Стандартний кеш Бітрікса (BXCache) повинен це закривати, але якщо кеш вимкнено або тегований кеш скидається часто — запити йдуть у БД. Рекомендації Бітрікс — використовувати тегований кеш.
Що дає кешування на рівні запитів?
Якщо дані змінюються раз на годину, немає сенсу ходити в БД на кожен запит. Використовуйте \Bitrix\Main\Data\Cache із тегованим кешем:
$cache = \Bitrix\Main\Data\Cache::createInstance(); $cacheId = 'catalog_top_' . $iblockId; $cachePath = '/catalog/top/'; if ($cache->initCache(3600, $cacheId, $cachePath)) { $data = $cache->getVars(); } elseif ($cache->startDataCache()) { $tagCache = new \Bitrix\Main\Data\TaggedCache(); $tagCache->startTagCache($cachePath); $data = /* ваш запит */; $tagCache->registerTag('iblock_id_' . $iblockId); $tagCache->endTagCache(); $cache->endDataCache($data); } При зміні будь-якого елемента інфоблоку тег автоматично інвалідується. Тегований кеш швидший за звичайний у 3–5 разів за часом інвалідації.
Оптимізація через D7 ORM
D7 ORM дає можливість точково керувати запитом. Порівняйте:
// Погано: завантажує всі поля, всі властивості $result = \Bitrix\Iblock\ElementTable::getList([ 'filter' => ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'], ]); // Краще: тільки потрібні поля, явний ліміт, кеш $result = \Bitrix\Iblock\ElementTable::getList([ 'select' => ['ID', 'NAME', 'PREVIEW_PICTURE_ID'], 'filter' => ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'], 'order' => ['SORT' => 'ASC'], 'limit' => 20, 'offset' => 0, 'cache' => ['ttl' => 3600], ]); Параметр cache у запиті ORM — вбудоване кешування. D7 ORM швидший за старий API у 2–3 рази на вибірках.
Робота з індексами
Додавання відсутніх індексів — найшвидше рішення з найбільшим ефектом. Ось таблиця найбільш корисних індексів:
| Таблиця | Рекомендований індекс | Коли потрібен |
|---|---|---|
b_iblock_element |
(IBLOCK_ID, ACTIVE, SORT) |
Майже завжди |
b_iblock_element_property |
(IBLOCK_PROPERTY_ID, VALUE) |
При фільтрації за властивостями |
b_sale_order |
(USER_ID, STATUS_ID, DATE_INSERT) |
Особистий кабінет покупця |
b_sale_basket |
(ORDER_ID, FUSER_ID) |
Кошик, оформлення замовлення |
b_search_content_stem |
(PARAM2) |
Пошук по великому каталогу |
Індекс додається через SQL або Бітрікс ORM:
$connection = \Bitrix\Main\Application::getConnection(); $connection->queryExecute( "ALTER TABLE b_iblock_element_property ADD INDEX ix_prop_val (IBLOCK_PROPERTY_ID, VALUE(64))" ); Обережно з VALUE(64): строкові поля індексуються за префіксом. Для числових значень розгляньте віртуальний стовпець. Докладніше — у статті Wikipedia про індекси БД.
Типові проблеми на проєктах: В одній компанії 6 місяців не могли зрозуміти, чому кошик гальмує на 10 секунд. Виявилося, запит до b_sale_basket без індексу по FUSER_ID. Додали індекс — час упав до 0.1 с. Інший проєкт: на сторінці списку замовлень (admin) виконувалося 10 000 запитів через N+1 у кастомному компоненті. Після рефакторингу — 50 запитів.
Строки робіт
| Задача | Обсяг робіт | Очікуваний ефект |
|---|---|---|
| Профілювання, виявлення топ-10 запитів | 1 день | Розуміння проблеми |
| Додавання відсутніх індексів | 1–2 дні | Прискорення в 2–10 разів на конкретних запитах |
Оптимізація $select у компонентах |
2–3 дні | Зниження навантаження на 20–40% |
| Усунення N+1, додавання кешу | 3–5 днів | Зниження кількості запитів у 3–5 разів |
| Комплекс: індекси + вибірка + кеш + ORM | 1–2 тижні | Сторінка з 500+ запитів → 50–100 запитів |
Що входить у роботу
- Аудит поточних SQL-запитів та виявлення вузьких місць.
- Розробка та реалізація індексів, оптимізація вибірок.
- Впровадження кешування та перехід на D7 ORM.
- Документація змін та рекомендації щодо моніторингу.
- Навчання розробників вашої команди.
- Гарантія 3 місяці на коректність оптимізації.
10 років досвіду, сертифікати Бітрікс та 200+ успішних проєктів гарантують якість. Кожен день високого навантаження коштує бізнесу значних коштів — оптимізація окупається за кілька місяців.
Замовте аудит під ключ — ми проаналізуємо ваш проект і запропонуємо рішення. Оцінимо ваш проект безкоштовно протягом 2 годин. Для замовлення напишіть на пошту або заповніть форму на сайті.







