Оптимизация запросов к highload-блокам 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Оптимизация запросов к highload-блокам 1С-Битрикс
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1173
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    745
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Оптимизация запросов к Highload-блокам 1С-Битрикс

HighLoad-блоки (модуль highloadblock) появились в Битрикс как ответ на производительные проблемы инфоблоков при хранении больших объёмов данных без иерархии. Каждый HL-блок — это отдельная MySQL-таблица с автогенерированным именем вида b_uts_catalog_props или пользовательским именем через настройки. В отличие от инфоблоков, HL-блоки не имеют сложных JOIN-зависимостей, и теоретически должны работать быстро. На практике медленные запросы к HL-блокам встречаются не реже — из-за отсутствия индексов, неправильного использования API и неудачной схемы данных.

Архитектура HL-блоков и точки роста

Таблица HL-блока содержит колонки ID, UF_* (пользовательские поля). При создании HL-блока через интерфейс Битрикс никаких индексов, кроме первичного ключа по ID, автоматически не создаётся. Это означает, что любой фильтр по полям, кроме ID, приводит к полному перебору таблицы (type = ALL в EXPLAIN).

Пример проблемного запроса:

$result = HighloadBlockTable::getList([
    'filter' => [
        '=UF_STATUS' => 'active',
        '>=UF_CREATED_AT' => new DateTime('-30 days'),
    ],
    'select' => ['ID', 'UF_NAME', 'UF_VALUE'],
    'order'  => ['UF_CREATED_AT' => 'DESC'],
    'limit'  => 50,
]);

Без индекса по UF_STATUS и UF_CREATED_AT этот запрос сканирует всю таблицу. При 500 000 записей — 300–800 мс на запрос.

Индексы для HL-блоков

Битрикс не предоставляет UI для создания индексов HL-блоков. Индексы создаются напрямую через SQL или через миграции. Для примера выше:

ALTER TABLE b_uts_my_highload
  ADD INDEX idx_status_created (UF_STATUS, UF_CREATED_AT);

Правила для выбора индексов:

  • Поля в filter — кандидаты для индексирования, но порядок важен: поле с меньшей кардинальностью (например, UF_STATUS с 3 значениями) ставится первым только если оно используется в запросах самостоятельно; иначе составной индекс начинается с высококардинального поля
  • Поля в order должны быть в индексе или покрывающем индексе
  • SELECT * заменяется на явный select с нужными полями — сокращает объём данных, иногда позволяет использовать covering index

Кеширование результатов HL-запросов

HL-блоки не имеют автоматического тегированного кеша, как инфоблоки. При использовании HighloadBlockTable::getList() кеширование нужно добавлять явно через ManagedCache:

$cache = \Bitrix\Main\Application::getInstance()->getManagedCache();
$cacheKey = 'hl_my_block_active_' . md5(serialize($filter));

if (!$cache->read(600, $cacheKey, 'hl_my_block')) {
    $result = MyHLTable::getList(['filter' => $filter, 'select' => $select]);
    $data = $result->fetchAll();
    $cache->set($cacheKey, $data);
} else {
    $data = $cache->get($cacheKey);
}

Инвалидация по тегу hl_my_block вызывается в обработчике OnAfterAdd / OnAfterUpdate HL-блока.

Пагинация на больших таблицах

Стандартная пагинация через offset деградирует на больших данных: OFFSET 50000 LIMIT 50 вынуждает MySQL прочитать и отбросить 50 000 записей. Для HL-блоков с десятками тысяч записей и бесконечной прокруткой или большим числом страниц используется cursor-based пагинация:

// Вместо offset используем последний ID
$result = MyHLTable::getList([
    'filter' => ['=UF_STATUS' => 'active', '>ID' => $lastId],
    'order'  => ['ID' => 'ASC'],
    'limit'  => 50,
]);

Это работает только при монотонном порядке сортировки по индексированному полю.

Кейс: хранение логов заказов в HL-блоке

Интернет-магазин использовал HL-блок как лог событий заказа: 3,2 млн записей, 8 полей. Запрос истории конкретного заказа (фильтр по UF_ORDER_ID) без индекса — 1,2 с. Добавление индекса по UF_ORDER_ID:

ALTER TABLE b_uts_order_log ADD INDEX idx_order_id (UF_ORDER_ID);

Время запроса: 1,2 с → 2 мс. Дополнительно: запросы сводной статистики за период (агрегация по UF_EVENT_TYPE за месяц) вынесены в отдельный кешируемый отчёт, обновляемый ночью — сняло нагрузку на MySQL в бизнес-часы.

Денормализация и HL-блоки как справочники

Часто HL-блоки используются как справочники (типы оплаты, статусы, регионы). При этом в основных запросах к инфоблоку делается JOIN с HL-блоком для получения текстового значения. Правильное решение — денормализация: хранить текстовое значение прямо в поле инфоблока, обновлять его при изменении справочника через агент. Это исключает JOIN в 95% запросов на чтение.

Этапы оптимизации

Работы Срок
Аудит запросов (slow query log, панель Битрикс) 0,5–1 день
Добавление индексов 0,5 дня
Переработка кеширования 1–3 дня
Рефакторинг схемы (денормализация, cursor пагинация) 2–5 дней

Начинать всегда с EXPLAIN — без него невозможно понять, нужен ли индекс и какой именно.