Производительность и частые ошибки
Проблемы при работе с API инфоблоков усиливаются по мере роста проекта: увеличиваются объем данных и число посещений. Сначала замедляется отдача страниц, затем растет нагрузка на базу данных. В итоге возникают сбои при сохранении данных и дубли в поисковой индексации.
Оптимизировать производительность инфоблоков
При работе с инфоблоками большинство проблем с производительностью возникает из-за избыточных данных: лишние поля, повторяющиеся запросы, неоптимальные фильтры. Начните оптимизацию с контроля над тем, что и как запрашиваете.
Ограничить выборку
Избыточный объем данных увеличивает время выполнения и потребление памяти. Указывайте только те поля, которые действительно нужны.
В компонентах
В компонентах избыточная выборка замедляет отдачу страницы и увеличивает размер кеша.
Например:
-
в
$arSelectилиselectесть поля, которые не используются в шаблоне компонента, -
выборка включает свойства
PROPERTY_*или служебные поля, которые не нужны для отображения.
Выполните проверку полей и внесите исправления.
-
Откройте папку с шаблоном компонента.
-
Найдите все обращения к
$arResult, особенно в циклах.<?= $arResult['ITEMS'][0]['ID'] ?> <?= $arResult['ITEMS'][0]['NAME'] ?> -
Укажите в
$arSelectилиselectполя из$arResult.- В классическом API:
// Получить ID и название без свойств и лишних полей CIBlockElement::GetList( [], ['IBLOCK_ID' => 123], false, false, ['ID', 'NAME'] );- В ORM:
\Bitrix\Iblock\ElementTable::getList([ 'select' => ['ID', 'NAME'], 'filter' => ['IBLOCK_ID' => 123], 'limit' => 20, 'cache' => [ 'ttl' => 3600, 'cache_joins' => true, ] ]);Такой кеш эффективен, если данные обновляются не чаще одного раза в час. При частом изменении элементов кеширование отключают.
Вне компонентов
Пример агента, который раз в час обновляет статистику по активным элементам.
function updateActiveElementsStat()
{
$cache = new \CPHPCache();
if ($cache->InitCache(3600, 'active_elements_count', '/stats/'))
{
$count = $cache->GetVars()['count'];
} else {
if ($cache->StartDataCache())
{
// Выбираем только ID и дату начала активности
$iterator = \Bitrix\Iblock\ElementTable::getList([
'select' => ['ID', 'DATE_ACTIVE_FROM'],
'filter' => [
'IBLOCK_ID' => 123,
'ACTIVE' => 'Y',
'>=ACTIVE_FROM' => ConvertTimeStamp(time() - 86400, 'FULL')
],
'limit' => 1000, // Защита от переполнения памяти
]);
$count = 0;
while ($element = $iterator->fetch())
{
$count++;
}
// Регистрируем тег для автоматического сброса при изменении инфоблока
$taggedCache = \Bitrix\Main\Application::getInstance()->getTaggedCache();
$taggedCache->startTagCache('/stats/');
$taggedCache->registerTag('iblock_id_123');
$taggedCache->endTagCache();
$cache->EndDataCache(['count' => $count]);
}
}
return true;
}
При изменении данных в инфоблоке вызовите сброс кеша:
$taggedCache = \Bitrix\Main\Application::getInstance()->getTaggedCache();
$taggedCache->clearByTag('iblock_id_123');
Выбрать подходящий метод получения данных
Метод GetNext() приводит данные к безопасному виду и обрабатывает шаблоны ссылок на элемент, раздел, инфоблок.
Метод Fetch() работает быстрее, чем GetNext(), но данные нужно обработать вручную.
Пример безопасного использования Fetch():
$row = $result->Fetch();
if ($row)
{
$row['NAME'] = \Bitrix\Main\Text\HtmlFilter::encode($row['NAME']);
}
Контролировать состав результата кеширования
По умолчанию компонент кеширует весь массив $arResult. Если $arResult содержит много полей или вложенных данных, размер кеш-файла растет, а скорость чтения падает.
Проверьте размер кеша.
-
В папке
/bitrix/cache/найдите папку кеша для компонента, например,news.list. -
Откройте самый свежий файл.
-
Посмотрите его размер. Если файл больше 1 МБ — кеш избыточен.
Сократите размер кеша за три шага.
-
В файле
component.phpобъявите только нужные поля:$this->SetResultCacheKeys(['ID', 'NAME', 'DATE_ACTIVE_FROM']); -
Убедитесь, что в
$arResultнет лишних полей. -
Обновите страницу и проверьте размер нового файла кеша.
Если в файле result_modifier.php формируют данные для component_epilog.php, их можно включить в кеш:
-
поместите данные в
$arResult, например,$arResult['IDS'] = [...]), -
добавьте ключ в
SetResultCacheKeys()вcomponent.php:$this->SetResultCacheKeys(['IDS']);
Использовать nTopCount вместо nPageSize
В методе CIBlockElement::GetList() четвертый параметр — это настройки навигации. Они позволяют ограничить выборку двумя способами:
-
nPageSize— задает количество элементов на странице при постраничной навигации,// Выполняет два запроса: COUNT (сколько всего) + SELECT (данные) CIBlockElement::GetList([], ['IBLOCK_ID' => 123], false, ['nPageSize' => 10], ['ID', 'NAME']); -
nTopCount— ограничивает общее число записей в результате запроса.// Выполняет один запрос: SELECT … LIMIT 10 CIBlockElement::GetList([], ['IBLOCK_ID' => 123], false, ['nTopCount' => 10], ['ID', 'NAME']);Если инфоблок хранит свойства в общей таблице, один элемент с множественными свойствами порождает несколько строк. Например, чтобы получить два элемента, у которых множественное свойство содержит два и три значения, установите
nTopCount = 5.
Используйте nTopCount в следующих ситуациях:
-
на странице нет постраничной навигации,
-
не нужно знать общее количество элементов,
-
на странице выводят фиксированное число элементов.
Разница в скорости заметна при большом количестве элементов в инфоблоке.
Избегать LIKE в фильтрах
Метод getList() без оператора = превращает фильтр в LIKE, например, 'CODE' => 'news'. Это замедляет запрос.
Чтобы отфильтровать записи по точному значению, укажите оператор =.
// Классический API
CIBlockElement::GetList([], [
'=CODE' => 'news'
]);
// ORM
\Bitrix\Iblock\ElementTable::getList([
'filter' => ['=CODE' => 'news']
]);
// query() автоматически использует %=
\Bitrix\Iblock\ElementTable::query()
->where('CODE', 'news')
->exec();
Проанализировать SQL-запросы
-
Откройте страницу Настройки > Производительность > SQL-запросы.
-
Найдите запросы внутри циклов. Это видно по повторяющемуся SQL-коду и большому количеству записей с одинаковым значением в столбце Компонент.
Чтобы исправить, соберите все идентификаторы в массив и сделайте один запрос с фильтром
['ID' => $ids]. -
Проверьте использование индексов.
-
Выберите подозрительный запрос и откройте План исполнения.

-
Если в строке
keyуказано<null>, а в условиях естьUsing filesortилиUsing temporary, запрос не использует индекс. -
Добавьте составной индекс по полям, которые часто фильтруют вместе:
IBLOCK_ID,ACTIVE,SORTилиIBLOCK_ID,CODE.
-
-
Найдите лишние подсчеты.
-
Ищите запросы вида
SELECT COUNT(*) FROM b_iblock_element. Если на странице нет постраничной навигации, такой запрос избыточен. -
Замените
nPageSizeнаnTopCountв параметрах навигации.
-
Вынести настройки выборки в параметры компонента
Когда один и тот же компонент используют на разных страницах, объем данных часто различается. Например:
-
на главной — только
IDиNAMEдля слайдера, -
в каталоге —
NAME,PREVIEW_TEXT,DETAIL_PAGE_URL.
Если указать список полей напрямую в коде, нужно создать копии компонента или внести правки в код под каждую задачу.
Чтобы избежать этого, вынесите список запрашиваемых полей в параметры компонента .parameters.php. Тогда состав выборки можно настроить в визуальном редакторе без изменения кода.
'PARAMETERS' => [
'SELECT_FIELDS' => [
'PARENT' => 'DATA_SOURCE',
'NAME' => 'Выбираемые поля',
'TYPE' => 'LIST',
'MULTIPLE' => 'Y',
'VALUES' => [
'ID' => 'ID',
'NAME' => 'Название',
'CODE' => 'Символьный код',
'DATE_ACTIVE_FROM' => 'Дата начала активности'
],
'DEFAULT' => ['ID', 'NAME']
]
]
В файле component.php используйте параметр SELECT_FIELDS:
$arSelect = $arParams['SELECT_FIELDS'] ?: ['ID', 'NAME'];
$res = CIBlockElement::GetList([], $filter, false, false, $arSelect);
Выполните настройку параметров компонента. Компонент будет запрашивать только те поля, которые действительно используются. Это сокращает объем передаваемых данных и ускоряет отдачу.
Частые ошибки при работе с инфоблоками
Ошибки при работе с инфоблоками имеют четкие признаки и стандартные решения.
Не подключен модуль
Если возникает ошибка Fatal error: Class 'ElementTable' not found или Fatal error: Class 'CIBlockElement' not found, модуль iblock не подключен.
Добавьте в начало скрипта:
\Bitrix\Main\Loader::includeModule('iblock');
Подключайте модуль, когда читаете или записываете элементы и разделы, работаете со свойствами, правами доступа, SEO-полями или связями между инфоблоками.
Не найден ORM-класс
Если возникает ошибка вида Class '\Bitrix\Iblock\Elements\ElementNewsTable' not found, у инфоблока не указан cимвольный код API.
Укажите API_CODE для инфоблока в административном разделе, сбросьте кеш и выполните компиляцию.
Не сохраняются значения свойств
Если свойства типа Список или Привязка к элементу не сохраняются, проверьте формат передаваемых значений и настройки инфоблока.
Свойство типа Список
Передайте ID значения из таблицы b_iblock_property_enum. Идентификатор можно получить методом CIBlockPropertyEnum::GetList().
Пример корректного сохранения элемента для инфоблока с 'API_CODE' => 'News':
$element = \Bitrix\Iblock\Elements\ElementNewsTable::createObject()
->setName('Новость')
->set('SOURCE', 105); // 105 — ID варианта в b_iblock_property_enum
$element->save();
Свойство типа Привязка к элементу
Первый способ. Передайте ID целевого элемента — универсальный способ.
$element = \Bitrix\Iblock\Elements\ElementNewsTable::createObject()
->setName('Обзор товара')
// RELATED_ITEM — код свойства типа Привязка к элементу
->set('RELATED_ITEM', 789); // 789 — ID элемента в инфоблоке Товары
$element->save();
Второй способ. Передайте XML_ID целевого элемента, если у целевого инфоблока задан API_CODE и скомпилирован ORM-класс. Например, \Bitrix\Iblock\IblockTable::compileEntity('Products').
$element = \Bitrix\Iblock\Elements\ElementNewsTable::createObject()
->setName('Обзор')
->set('RELATED_ITEM', 'product-2026'); // XML_ID из инфоблока Товары
$element->save();
Проверьте:
-
у свойства типа
Привязка к элементууказан инфоблок привязкиLINK_IBLOCK_ID, -
целевой элемент существует и активен,
-
для множественных свойств используйте
addTo('CODE', значение), а неset().
Переменная не является объектом
Если возникает ошибка Call to a member function GetNextElement() on a non-object, нарушен порядок или тип параметров в вызове CIBlockElement::GetList().
Используйте правильную сигнатуру:
CIBlockElement::GetList(
[], // сортировка
$arFilter, // фильтр
false, // группировка: только true/false
false, // параметры навигации: массив или false
$arSelect // выборка полей
);
Страница возвращает неверный код
Если несуществующая страница элемента возвращает код состояния 200 OK, поисковые системы ее индексируют.
Чтобы исправить проблему, в шаблоне компонента до вывода HTML установите код 404:
if (!$arResult['ELEMENT'])
{
\CHTTP::SetStatus('404 Not Found');
require $_SERVER['DOCUMENT_ROOT'].'/404.php';
exit;
}