Реальна проблема: повільні запити до інфоблоків
Ми часто стикаємося з проектами, де каталог на Бітрікс гальмує через неоптимальні запити до інфоблоків. Типова картина: сторінка списку товарів з 48 позиціями завантажується 2-3 секунди, хоча MySQL сервер не навантажений. Стандартний CIBlockElement::GetList з фільтрацією за властивостями генерує кілька JOIN-ів, і при 100 товарах з 5 властивостями EXPLAIN показує перебір сотень тисяч рядків. TTFB перевищує 1 секунду навіть на VPS з 4 vCPU. Платформа 1С-Бітрікс — одна з популярних CMS для інтернет-магазинів, однак її інфоблоки часто стають вузьким місцем. У нашій практиці, що налічує понад 50 оптимізованих проектів, 90% проблем вирішуються переходом на D7 ORM і правильною розстановкою індексів. Це дозволяє знизити витрати на серверні ресурси та вкластися в бюджет без зайвих вкладень. Ми гарантуємо зниження часу запитів в 3-5 разів. Ця стаття — результат нашого багаторічного досвіду.
Чому стандартні запити Бітрікс гальмують?
Старий API CIBlockElement::GetList при вказанні PROPERTY_* фільтра додає JOIN для кожної властивості. Якщо у фільтрі 5 властивостей — 5 JOIN-ів. План запиту стає неоптимальним, особливо коли таблиця b_iblock_element_property містить мільйони записів. Крім того, параметр arSelect зі значенням "*" або без явного списку змушує API тягнути всі поля, включаючи довгі тексти PREVIEW_TEXT і DETAIL_TEXT. В результаті обсяг даних з БД зростає в 3–5 разів.
Ще одна поширена помилка — N+1 запит. Після отримання списку елементів розробники часто в циклі викликають CIBlockElement::GetProperty() для кожного товару. При 48 товарах це 1 + 48 = 49 запитів. Час виконання зростає лінійно.
Як впровадити батчеву вибірку без регресії?
Перехід на \Bitrix\Iblock\ElementTable з D7 ORM дає повний контроль над SQL. Кожен запит можна перевірити через getQuery()->getSql() до виконання. Приклад оптимального запиту для сторінки каталогу:
use Bitrix\Iblock\ElementTable; $result = ElementTable::getList([ 'select' => [ 'ID', 'NAME', 'CODE', 'PREVIEW_PICTURE', 'IBLOCK_SECTION_ID', ], 'filter' => [ '=IBLOCK_ID' => CATALOG_IBLOCK_ID, '=ACTIVE' => 'Y', '=IBLOCK_SECTION_ID' => $sectionId, ], 'order' => ['SORT' => 'ASC', 'ID' => 'ASC'], 'limit' => 24, 'offset' => $page * 24, 'cache' => ['ttl' => 3600], ]); Explicit select без властивостей — запит тільки до b_iblock_element, без JOIN. Якщо потрібні значення властивостей для кількох товарів, ми використовуємо батчеву вибірку за ID:
$ids = array_column($elements, 'ID'); $propsResult = \CIBlockElement::GetPropertyValuesArray( $ids, CATALOG_IBLOCK_ID, ['CODE' => ['BRAND', 'COLOR', 'SIZE']] ); Цей патерн «запит за ID батчами» вирішує N+1 проблему. Офіційна документація по D7 ORM містить всі деталі. 1С-Бітрікс Academy
Кейс з нашої практики: каталог будматеріалів 45 000 SKU
Ми працювали з клієнтом — інтернет-магазином будматеріалів. Каталог містив 45 000 активних позицій. Сторінка розділу з 48 товарами завантажувалася 1,8 секунди без кешу. MySQL slow query log показав кілька проблем:
-
CIBlockElement::GetListзSELECT => "*"іPROPERTY_FILTERна 5 властивостей давав 640 мс на один запит. - Блок «схожі товари» виконував окремий запит для кожного з 6 товарів (N+1).
- Запит дерева розділів не мав обмеження за рівнем.
Ми виконали такі дії:
- Переписали основний запит на D7, залишивши тільки 8 необхідних полів.
- Замінили потокові запити властивостей на батчеву вибірку через
GetPropertyValuesArray. - Обмежили
DEPTH_LEVELу вибірці розділів і додали тегований кеш. - Створили складений індекс на
b_iblock_element:
ALTER TABLE b_iblock_element ADD INDEX idx_iblock_section_active_sort (IBLOCK_ID, IBLOCK_SECTION_ID, ACTIVE, SORT); Результат: TTFB сторінки розділу без кешу впав з 1,8 с до 380 мс, з кешем — до 45 мс. Кількість запитів до БД скоротилася з 12 до 4. Навантаження на MySQL знизилося в 3 рази, що дозволило клієнту заощадити до 30% на серверних потужностях. Клієнт отримав можливість обслуговувати більше відвідувачів без збільшення витрат.
Порівняння старого та нового підходу
| Параметр | CIBlockElement::GetList | D7 ORM + батчі |
|---|---|---|
| Кількість JOIN при фільтрі за 5 властивостями | 5 | 0 (якщо властивості не в select) |
| Контроль SQL | Немає | Повний (getQuery()->getSql()) |
| N+1 ризик | Високий | Усувається батчевою вибіркою |
| Кешування | Тільки файлове | Теговане + data cache |
| Продуктивність (приклад) | 640 мс | 80 мс |
D7 API в 3–5 разів швидше при типових запитах.
Що входить у роботу з оптимізації
Ми пропонуємо комплексну оптимізацію запитів до інфоблоків під ключ. До складу робіт входить:
- Аналіз slow query log MySQL і панелі продуктивності Бітрікс.
- Аудит усіх кастомних компонентів на предмет N+1 та неоптимальних вибірок.
- Переписування критичних запитів на D7 ORM з явним select і батчевими стратегіями.
- Додавання необхідних складених індексів та налаштування тегованого кешу.
- Створення документації з оптимізованих запитів для вашої команди.
- Навчання розробників роботі з D7 та найкращим практикам.
Детальніше про наш досвід
Ми займаємося Бітрікс-розробкою понад 10 років, сертифіковані 1С-Бітрікс. Успішно оптимізували каталоги для 20+ великих проектів з трафіком від 10 000 відвідувачів на день.Терміни та вартість
| Етап | Термін |
|---|---|
| Аудит запитів (slow log, Explain, панель Бітрікс) | 1–2 дні |
| Переробка критичних запитів (D7, batching) | 3–7 днів |
| Індекси та налаштування кешу | 1–2 дні |
| Документація та навчання | 1 день |
Вартість розраховується індивідуально залежно від обсягу каталогу та кількості компонентів. Зв'яжіться з нами для оцінки вашого проекту — це займе 2 дні. Отримайте консультацію щодо прискорення вашого каталогу.







