Highload-блоки в Битрикс — это эффективный инструмент для работы с крупными объемами данных, значительно превосходящий стандартные инфоблоки по производительности, особенно в условиях высоких нагрузок. Они оптимизированы для хранения и обработки больших объемов информации, используя подход, схожий с NoSQL-хранилищами. Взаимодействие с данными Highload-блоков осуществляется через объектно-ориентированные модели (ORM), что позволяет выполнять операции создания, чтения, обновления и удаления (CRUD) с помощью объектных методов.
Класс Bitrix\Main\ORM\Query\Query в рамках ORM Битрикс D7 предоставляет мощные возможности для построения сложных запросов к данным, включая Highload-блоки, обеспечивая гибкость и контроль над формированием SQL-запросов.
Для построения сложных запросов к Highload-блокам с использованием Bitrix\Main\ORM\Query\Query необходимо выполнить несколько ключевых шагов.
1. Подключение модуля Highload-блоков
Перед началом работы с Highload-блоками через D7 API обязательно подключите модуль highloadblock.
<?php
use Bitrix\Main\Loader;
use Bitrix\Highloadblock as HL;
use Bitrix\Main\Entity;
use Bitrix\Main\ORM\Query\Query;
Loader::includeModule("highloadblock");
?>2. Получение сущности Highload-блока
Каждый Highload-блок представляет собой уникальную сущность, с которой работает ORM. Для получения этой сущности требуется знать ID или название Highload-блока.
<?php
$hlBlockId = 1; // Замените на ID вашего Highload-блока
$hlblock = HL\HighloadBlockTable::getById($hlBlockId)->fetch();
if (!$hlblock) {
    throw new \Exception("Highload-блок с ID " . $hlBlockId . " не найден.");
}
$entity = HL\HighloadBlockTable::compileEntity($hlblock);
$dataClass = $entity->getDataClass();
?>3. Создание объекта Query и построение запроса
После получения класса DataManager для Highload-блока можно приступать к формированию запросов. Несмотря на то, что метод getList() широко используется, Bitrix\Main\ORM\Query\Query предоставляет более широкие возможности для конструирования сложных запросов.
Примеры построения сложных запросов:
Выборка с фильтрацией, сортировкой и ограничением
Методы setSelect() для указания выбираемых полей, setFilter() для фильтрации данных, setOrder() для сортировки и setLimit() для ограничения количества записей являются основными при работе с классом Query.
<?php
$query = new Query($entity);
$query->setSelect(['ID', 'UF_NAME', 'UF_VALUE']); // Выбираем поля ID, UF_NAME, UF_VALUE
$query->setFilter([
    '=UF_CATEGORY' => 10, // Фильтр по UF_CATEGORY, равный 10
    '>UF_PRICE' => 1000  // Фильтр по UF_PRICE, больше 1000
]);
$query->setOrder(['UF_NAME' => 'ASC']); // Сортировка по UF_NAME по возрастанию
$query->setLimit(10); // Ограничение на 10 записей
$result = $query->exec();
while ($row = $result->fetch()) {
    print_r($row);
}
?>Использование логических операторов в фильтре
Условия в фильтре можно комбинировать с помощью логического оператора LOGIC (OR или AND).
<?php
$query = new Query($entity);
$query->setSelect(['ID', 'UF_PRODUCT_NAME']);
$query->setFilter([
    'LOGIC' => 'OR',
    ['=UF_STATUS' => 'active'],
    ['=UF_STATUS' => 'pending', '>UF_DATE_CREATED' => '2025-01-01']
]);
$result = $query->exec();
while ($row = $result->fetch()) {
    print_r($row);
}
?>Объединение таблиц (JOIN)
Для связывания Highload-блоков с другими сущностями (например, инфоблоками или другими Highload-блоками) используется динамическая регистрация полей через registerRuntimeField с типом ReferenceField. Класс Bitrix\Main\ORM\Query\Join предоставляет методы для определения условий объединения, например, on().
<?php
use Bitrix\Main\Entity\ReferenceField;
use Bitrix\Iblock\ElementTable; // Пример для инфоблоков
$query = new Query($entity);
$query->setSelect([
    'ID',
    'UF_ELEMENT_ID',
    'ELEMENT_NAME' => 'ELEMENT.NAME', // Выбираем название элемента из связанной сущности
]);
$query->registerRuntimeField(
    'ELEMENT',
    new ReferenceField(
        'ELEMENT',
        ElementTable::class, // Класс сущности, с которой связываем
        ['=this.UF_ELEMENT_ID' => 'ref.ID'], // Условие связи (this - текущий HL-блок, ref - связанная сущность)
        ['join_type' => 'inner'] // Тип JOIN (inner, left, right)
    )
);
$query->setFilter(['=ELEMENT.IBLOCK_ID' => 5]); // Фильтр по ID инфоблока
$result = $query->exec();
while ($row = $result->fetch()) {
    print_r($row);
}
?>Группировка и агрегатные функции
Возможность группировки данных с помощью setGroup() и выполнения агрегатных функций (таких как COUNT, AVG, SUM, MAX, MIN) через Entity\ExpressionField в setSelect() значительно расширяет функционал запросов.
<?php
$query = new Query($entity);
$query->setSelect([
    'UF_CATEGORY',
    new Entity\ExpressionField('COUNT_ITEMS', 'COUNT(%s)', 'ID'), // Подсчет элементов
    new Entity\ExpressionField('AVG_PRICE', 'AVG(%s)', 'UF_PRICE') // Средняя цена
]);
$query->setGroup(['UF_CATEGORY']);
$result = $query->exec();
while ($row = $result->fetch()) {
    print_r($row);
}
?>Runtime-поля (runtime section) в Query или getList позволяют динамически регистрировать новые поля для конкретного запроса. Это могут быть ExpressionField для вычислений или поля других типов, что фактически расширяет карту сущности на время выполнения запроса и особенно полезно для объединения данных из различных Highload-блоков без изменения их оригинальных ORM-моделей.
Важные моменты и лучшие практики при работе с ORM и Highload-блоками
- Явное указание полей: Всегда явно указывайте поля в 
setSelect(). Это позволяет избежать избыточной выборки данных, что положительно сказывается на производительности. - Использование операторов: Для точного соответствия используйте оператор 
=. Отсутствие явного оператора может привести к использованиюLIKEБитриксом по умолчанию, что замедляет запросы. - Множественные поля: Работа с полями типа «множественное» требует особого внимания, так как они могут храниться в сериализованном виде или в отдельных таблицах. Учитывайте это при построении запросов.
 - Отслеживание запросов: Для отладки и оптимизации используйте 
Application::getConnection()->startTracker()иgetTrackerQuery()->getSql()для просмотра сгенерированного SQL-запроса. Это помогает понять, какой именно SQL-запрос выполняется. - Производительность и кэширование: Хотя Highload-блоки созданы для высоких нагрузок, при очень больших объемах данных может потребоваться дополнительная оптимизация базы данных (индексация) и кэширование. ORM Битрикс поддерживает кэширование запросов с параметром 
ttl(time to live), включая запросы с JOIN’ами. Кэш автоматически сбрасывается при операцияхadd,update,deleteи может быть очищен вручную черезcleanCache()для сущности. - Обработчики событий Highload-блоков: Highload-блоки поддерживают различные события (
OnBeforeAdd,OnAfterAdd,OnBeforeUpdate,OnAfterUpdate,OnBeforeDelete,OnAfterDelete). Эти события позволяют внедрять пользовательскую логику до или после операций изменения данных, что дает возможности для валидации, модификации данных или выполнения дополнительных действий. - Структура класса 
Query: КлассBitrix\Main\ORM\Query\Queryсодержит множество защищенных методов (buildSelect(),buildJoin(),buildWhere(),buildGroup(),buildHaving(),buildOrder()), которые отвечают за построение соответствующих частей SQL-запроса, а также управляет внутренними цепочками для различных условий запроса. Понимание их предназначения может быть полезно для глубокой отладки. 
Использование Bitrix\Main\ORM\Query\Query с Highload-блоками обеспечивает мощный и гибкий инструмент для работы с данными, позволяя эффективно строить даже самые сложные запросы.
