Инфоблоки в Битрикс: выборки, свойства и кеш без боли
Список из 20 карточек легко превращается в сотни SQL-запросов, если свойства читать по одному, а справочники хранить не там. Разбираем три способа выборки, типы свойств и кеш инфоблоков Битрикс.

Страница каталога выводит 20 карточек, а в отладке видны сотни SQL-запросов: по одному на свойство каждого товара. Причина обычно не в железе, а в том, как спроектирован инфоблок и как из него читают. Ниже три способа выборки с их ценой, правила выбора типа свойства и места, где инфоблок на проде ломается чаще всего. Материал написан для «1С-Битрикс: Управление сайтом» 23.x и PHP 8.1. В другой редакции сверяйте имена с документацией модуля iblock.
Сначала проверьте, как хранятся свойства
У инфоблока есть версия хранения свойств. В версии 1.0 значения всех свойств лежат в одной общей таблице b_iblock_element_property. Фильтр по двум-трём свойствам превращается в несколько соединений с ней, и на большом каталоге тормозит именно это. В версии 2.0 одиночные свойства лежат в таблице b_iblock_element_prop_s с номером инфоблока, множественные в b_iblock_element_prop_m. Одиночные свойства читаются почти как обычные колонки.
Цена у 2.0 тоже есть: добавление одиночного свойства меняет структуру таблицы, и на большом инфоблоке это заметно. Для каталога с устоявшейся схемой выбор очевиден. Для блога на сотню записей разницы нет. Конвертация штатная, но делайте её после резервной копии и в окно с низкой нагрузкой.
Три способа достать элементы
CIBlockElement::GetList
Старый API есть в каждом проекте и внутри штатных компонентов. Главная ловушка: GetProperty в цикле. Свойство нужно просить в select.
use Bitrix\Main\Loader;
Loader::includeModule('iblock');
$iblockId = 5; // ID вашего инфоблока
// Плохо: отдельный запрос свойства на каждый элемент
$res = CIBlockElement::GetList(['SORT' => 'ASC'], ['IBLOCK_ID' => $iblockId, 'ACTIVE' => 'Y'], false, ['nTopCount' => 20], ['ID', 'NAME']);
while ($item = $res->Fetch()) {
$brand = CIBlockElement::GetProperty($iblockId, $item['ID'], ['sort' => 'asc'], ['CODE' => 'BRAND'])->Fetch();
}
// Лучше: свойство в select, значение придёт в PROPERTY_BRAND_VALUE
$res = CIBlockElement::GetList(['SORT' => 'ASC'], ['IBLOCK_ID' => $iblockId, 'ACTIVE' => 'Y'], false, ['nTopCount' => 20], ['ID', 'NAME', 'PROPERTY_BRAND']);
while ($item = $res->Fetch()) {
$brand = $item['PROPERTY_BRAND_VALUE'];
}Есть два нюанса. Множественное свойство в select размножает строки: элемент придёт столько раз, сколько у него значений. И GetNext(), в отличие от Fetch(), экранирует HTML и добавляет ключи с тильдой с исходными значениями.
ElementTable
Класс Bitrix\Iblock\ElementTable это ORM-сущность таблицы элементов. Он видит только поля элемента (ID, NAME, CODE, ACTIVE, IBLOCK_ID), зато не тянет лишнего. Для автокомплита, карты сайта и проверки «есть ли такой элемент» это самый дешёвый путь. Он читает таблицу напрямую и не применяет права доступа Битрикса, так что проверку прав нужно делать самим.
ORM по символьному коду API
Если у инфоблока задан «Символьный код API», Битрикс генерирует для него ORM-класс со свойствами. Получить его проще через Iblock::wakeUp, не угадывая имя.
use Bitrix\Main\Loader;
use Bitrix\Iblock\Iblock;
Loader::includeModule('iblock');
// У инфоблока должен быть задан «Символьный код API», иначе класса не будет
$dataClass = Iblock::wakeUp(5)->getEntityDataClass();
$rows = $dataClass::getList([
'select' => ['ID', 'NAME', 'BRAND_VALUE' => 'BRAND.VALUE'],
'filter' => ['=ACTIVE' => 'Y'],
'order' => ['SORT' => 'ASC'],
'limit' => 20,
])->fetchAll();Имя свойства в запросе берётся из его символьного кода. Как вести себя с множественными свойствами в вашей версии, смотрите в документации по ORM инфоблоков.
Сравнение
| Подход | Свойства | Что получаете | Чем платите |
|---|---|---|---|
| CIBlockElement::GetList | PROPERTY_КОД в select | Работает везде, понятен всем | Дубли при множественных свойствах, тяжёлые фильтры на 1.0 |
| ElementTable | Нет | Минимум запросов | Свойства отдельно, права не проверяются |
| ORM по API_CODE | КОД.VALUE | Единый синтаксис ORM | Нужен код API, больше проверок на своей версии |
Тип свойства решает больше, чем кажется
- Список подходит для 5-20 стабильных значений вроде статуса.
- Справочник на базе highload-блока нужен для брендов, цветов, размеров. Значения лежат в отдельной таблице, их можно держать тысячами.
- Привязка к элементу нужна, когда у связанной сущности есть своя страница и поля: автор, производитель.
- Свободная строка там, где нужен фильтр, это «Samsung», «SAMSUNG» и «Самсунг» в трёх разных товарах.
Инфоблок ведёт себя как таблица ровно до тех пор, пока вы не начнёте фильтровать его по свойствам.
Умный фильтр каталога держится на фасетном индексе. Без него фильтр по свойствам каждый раз собирает выборку заново.
Фасетный индекс. Служебные таблицы, где заранее хранятся сочетания значений свойств и подходящие им элементы. Они позволяют фильтру быстро считать, сколько товаров останется после выбора очередного значения. Включается в настройках инфоблока, точное место ищите в документации своей редакции.
Кеш: где теряется выигрыш
У штатных компонентов есть параметры CACHE_TYPE, CACHE_TIME и CACHE_GROUPS. Последний, «Учитывать права доступа», по умолчанию включён: кеш хранится отдельно для каждой комбинации групп пользователя. На сайте с десятком групп кеш одной страницы размножается во столько же раз. Если весь контент публичный, параметр можно отключить. Если часть элементов закрыта по правам, не отключайте его, иначе закрытое уйдёт всем. В собственном коде теговый кеш приходится регистрировать вручную. Иначе правка элемента не сбросит кеш, и данные будут устаревшими до конца времени жизни.
Когда что выбирать
- Страница на штатных компонентах (
news.list,catalog.section): не переписывайте, настройте кеш и выборку свойств. - Новая собственная выборка со свойствами: ORM по API_CODE.
- Нужны только ID, название и код: ElementTable.
- У данных нет детальной страницы, разделов, прав и SEO (заявки, логи, длинные справочники): держите их в highload-блоке, а не в инфоблоке.
Что ломается
- Обработчик
OnAfterIBlockElementUpdateвызывает обновление того же элемента и уходит в рекурсию. Нужен флаг защиты от повторного входа. - ID инфоблока зашит в код: на dev это 5, на проде 12. Берите по символьному коду или API_CODE.
- Агент видит меньше элементов, чем админка. Проверьте
CHECK_PERMISSIONSв фильтреGetList. - Удаление свойства стирает значения во всех элементах. Без резервной копии это необратимо.
- Смена символьного кода свойства ломает все
PROPERTY_КОДв шаблонах и своём коде.
Что делать дальше
Включите отладку и посмотрите число запросов на самой тяжёлой странице списка. Запишите время ответа с холодным и тёплым кешем, потом меняйте по одному: сначала select со свойствами, затем версию хранения, затем кеш. Проверьте, включён ли фасетный индекс у каталога с умным фильтром. Тонкая настройка индекса и инвалидация кеша это отдельные темы, здесь они не разбираются.
Аналитик звонков: Разбор записи звонка по этапам сделки: где сорвалось, что упущено, три исправляемые рекомендации с цитатами.
Спросить за 90 ₽Источники: 1С-Битрикс: документация, CIBlockElement::GetList, Документация 1С-Битрикс: ORM инфоблоков и символьный код API (раздел модуля iblock)
Частые вопросы
Как понять, какая версия хранения у моего инфоблока?
Безопасно ли конвертировать инфоблок в версию 2.0 на работающем сайте?
А если у меня другая версия Битрикса и ORM не находит класс инфоблока?
Почему в GetList один элемент приходит несколько раз?
Что проверить на проде перед релизом изменений в инфоблоке?
Нужно ли полностью переходить на D7?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.