Highload-блоки — механизм хранения больших справочников в отдельных таблицах с доступом через ORM. В их основе лежит динамически скомпилированная сущность, которую разработчик получает во время выполнения.
Что такое Highload-блок
Highload-блок (HL-блок) — это сущность модуля highloadblock, предназначенная для справочников с большим числом записей: города, характеристики, бренды, торговые предложения. В отличие от инфоблоков, HL-блок хранит данные в собственной отдельной таблице и не тащит на себе универсальную, но тяжёлую схему инфоблоков.
- своя таблица в БД под каждый HL-блок — без общих EAV-таблиц;
- доступ через ORM — быстрый и типизированный;
- пользовательские поля (UF) как колонки, с привычным интерфейсом настройки;
- подходит для миллионов строк, где инфоблок был бы медленным.
Устройство: таблица описаний и UF-поля
Сам список HL-блоков хранится в таблице b_hlblock_entity (ORM-класс Bitrix\Highloadblock\HighloadBlockTable). Каждая запись описывает имя ORM-сущности и имя реальной таблицы данных.
| Что | Где хранится |
|---|---|
| Список HL-блоков | таблица b_hlblock_entity |
| Данные HL-блока | отдельная таблица, напр. b_hl_brand |
| Пользовательские поля | система UF (b_user_field) |
Поля HL-блока — это пользовательские поля (User Field), привязанные к сущности HLBLOCK_{ID}. Они становятся колонками таблицы данных и попадают в карту ORM-сущности при компиляции.
Компиляция ORM-сущности
У HL-блока нет заранее написанного Table-класса — сущность собирается динамически на основе описания и UF-полей. Ключевой шаг: получить описание и вызвать компиляцию.
use Bitrix\Main\Loader;
use Bitrix\Highloadblock\HighloadBlockTable as HLBT;
Loader::includeModule('highloadblock');
$hlblock = HLBT::getById(3)->fetch(); // по ID блока
$entity = HLBT::compileEntity($hlblock);
$dataClass = $entity->getDataClass(); // строка с именем классаМетод compileEntity() возвращает объект Entity, а getDataClass() — имя динамического класса-наследника DataManager. Через это имя доступны все стандартные методы ORM: getList(), add(), update(), delete().
Выборка и запись данных
После компиляции работа с HL-блоком не отличается от обычной ORM-сущности. Разница лишь в том, что класс — строка, поэтому методы вызываются через переменную.
$rows = $dataClass::getList([
'select' => ['ID', 'UF_NAME', 'UF_CODE'],
'filter' => ['=UF_ACTIVE' => 1],
'order' => ['UF_SORT' => 'ASC'],
'limit' => 100,
])->fetchAll();
$add = $dataClass::add([
'UF_NAME' => 'ACME',
'UF_CODE' => 'acme',
'UF_ACTIVE' => 1,
]);
$id = $add->getId();Имена полей HL-блока начинаются с префикса UF_, потому что это пользовательские поля. Первичный ключ ID присутствует всегда.
Создание HL-блока из кода
HL-блок можно создать не только в админке, но и программно — при установке модуля или миграции. Сначала регистрируется сам блок, затем добавляются UF-поля.
use Bitrix\Highloadblock\HighloadBlockTable as HLBT;
$result = HLBT::add([
'NAME' => 'Brand', // имя сущности, с заглавной, латиница
'TABLE_NAME' => 'b_hl_brand', // имя таблицы данных
]);
$hlId = $result->getId();
// далее добавляем UF-поля через CUserTypeEntity::Add
$oField = new \CUserTypeEntity();
$oField->Add([
'ENTITY_ID' => 'HLBLOCK_' . $hlId,
'FIELD_NAME' => 'UF_NAME',
'USER_TYPE_ID' => 'string',
'MANDATORY' => 'Y',
]);NAME HL-блока должно начинаться с заглавной буквы и содержать только латиницу и цифры — это имя PHP-класса сущности. Имя таблицы задаётся отдельно в TABLE_NAME.Производительность и индексы
HL-блоки создавались ради скорости на больших объёмах, но выигрыш реализуется только при правильных индексах. По умолчанию UF-поля индексов не получают.
- добавляйте индексы на поля, по которым фильтруете и сортируете;
- для уникальных кодов используйте уникальный индекс — это и защита от дублей;
- кэшируйте частые выборки через
setCacheTtl(), инвалидируя по тегам; - не выбирайте все поля через
*на широких таблицах; - для массового импорта используйте пакетную вставку и транзакции.
Индексы удобно создавать в файле миграции через Application::getConnection()->query('CREATE INDEX ...'), поскольку интерфейс HL-блоков их не настраивает автоматически.
Когда выбирать HL-блок
HL-блок — не универсальная замена инфоблокам. У них разные сильные стороны.
| Критерий | Инфоблок | Highload-блок |
|---|---|---|
| Разделы/дерево | есть из коробки | нет |
| Готовые компоненты | много | почти нет |
| Скорость на млн строк | средняя | высокая |
| Схема хранения | универсальная (EAV) | плоская таблица |
Выбирайте HL-блок для больших плоских справочников без иерархии и сложного контент-управления. Для каталога с разделами, привязками и витриной удобнее инфоблок.
Итог
Модель данных HL-блоков — это отдельная таблица на справочник, UF-поля как колонки и динамически скомпилированная ORM-сущность, получаемая через compileEntity() и getDataClass(). Дальше работа идёт стандартными методами ORM. Скорость на больших объёмах достигается только при продуманных индексах и кэше.
Мы в B2Bsite проектируем highload-каталоги и справочники на HL-блоках: подбираем индексы, настраиваем кэш и пакетный обмен под миллионы записей. Если проект растёт в объёме данных и упирается в производительность — поможем перестроить модель и выдержать нагрузку.
Частые вопросы
Чем Highload-блок отличается от инфоблока?
HL-блок хранит данные в собственной плоской таблице с доступом через ORM, без EAV-схемы и без разделов. Он быстрее на больших объёмах, но лишён готовых компонентов и дерева разделов инфоблоков.
Как получить ORM-класс HL-блока?
Подключить модуль highloadblock, взять описание через HighloadBlockTable::getById, скомпилировать сущность методом compileEntity и получить имя класса через getDataClass. Дальше работать стандартными методами ORM.
Почему поля HL-блока начинаются с UF_?
Потому что это пользовательские поля (User Field), привязанные к сущности HLBLOCK_{ID}. Они становятся колонками таблицы данных и попадают в карту ORM при компиляции.
Можно ли создать HL-блок из кода?
Да. Через HighloadBlockTable::add регистрируется блок с именем и таблицей, а поля добавляются через CUserTypeEntity::Add с ENTITY_ID вида HLBLOCK_{ID}. Это удобно в миграциях.
Нужны ли индексы в HL-блоке?
Обязательно. UF-поля по умолчанию не индексируются, поэтому фильтры и сортировки без индексов деградируют на объёме. Индексы создают вручную через SQL, обычно в миграции.
Для чего лучше подходят HL-блоки?
Для больших плоских справочников без иерархии: характеристики, бренды, города, торговые предложения. Для каталога с разделами и витриной удобнее инфоблок с его компонентами.
Как ускорить выборки из HL-блока?
Добавить индексы под фильтры, ограничивать select, кэшировать частые запросы через setCacheTtl с инвалидацией по тегам, а массовый импорт делать пакетно и в транзакции.
Поможем с настройкой и поддержкой Для разработчиков
Поможем с настройкой, доработкой и поддержкой Для разработчиков.