Как кешировать выборки D7 ORM в 1С-Битрикс через cache в getList?

Как кешировать выборки D7 ORM в 1С-Битрикс через cache в getList?

Тяжёлый getList() на справочнике городов тормозит каждый хит — типичная проблема после "cache" с ttl 3600: витрина показывает вчерашний список, хотя в админке всё поправили. Встроенный ORM-кеш в 1С-Битрикс: Управление сайтом ускоряет повторяющиеся выборки через ключ cache в getList, но требует cache_joins, cleanCache() и cache_flags. Ниже - гайд: включите кеш на staging, проверьте managed_cache и сбрасывайте выборку точечно, без "Очистить весь кеш".

Встроенный ORM-кеш доступен с main 16.5.9: передайте "cache" => ["ttl" => N] в getList, getRow или getByPrimary. Файлы лежат в /bitrix/managed_cache/MYSQL/orm_<table>/, ключ - md5(sql). После add, update, delete через DataManager кеш сбрасывается сам; после raw SQL или импорта вызовите Table::cleanCache(). JOIN без cache_joins не кешируется. Права пользователя в ключ не входят - учитывайте это в filter.

Речь про коробочную CMS, не про CRM-портал Bitrix24. ORM (Object-Relational Mapping) - слой D7, который связывает PHP-класс *Table с таблицей MySQL. Простую выборку инфоблока разобрали в сравнении GetList и ElementTable (B60). Сложные отчёты с агрегацией - в гайде по Query и ExpressionField (B83). Здесь - только встроенный кеш выборок DataManager, без обзора всех видов кеша.

Выберите, когда нужен ORM cache, а не TaggedCache или полная очистка

Сравнение ORM cache, TaggedCache и полной очистки кеша в Битрикс

ORM-кеш ускоряет повторяющиеся getList() на своих Table или HL DataClass в сервисе модуля. Это не registerTag в шаблоне и не кнопка в админке.

Механизм Где включается Когда использовать
ORM cache (cache в getList) DataManager::getList / getRow Тяжёлая выборка из одной ORM-талицы, одинаковая для всех посетителей
TaggedCache / registerTag Компонент, result_modifier HTML-блок витрины с тегами iblock_* - см. гайд по тегированному кешу (B66)
Очистка через админку Настройки - Производительность Аварийный сброс всего managed cache - когда и как чистить кеш (B20)

Делайте: кешируйте ORM-выборку, если один и тот же SQL уходит на каждый хит и данные меняются через DataManager. Не делайте: не путайте CityTable::cleanCache() с clearByTag из B66 и не жмите "Очистить весь кеш" при каждой правке справочника.

Включите cache в getList и проверьте managed_cache на диске

Чеклист включения ORM cache в getList и проверки managed_cache на диске

По умолчанию кеширование выборок ORM отключено. Минимальный рабочий пример - ttl в секундах:

use Bitrix\Main\GroupTable;

$result = GroupTable::getList([
    'select' => ['ID', 'NAME'],
    'filter' => ['=ACTIVE' => 'Y'],
    'order'  => ['C_SORT' => 'ASC'],
    'cache'  => ['ttl' => 3600],
]);

Тот же ключ cache работает в getRow() и getByPrimary(). Второй хит читается из /bitrix/managed_cache/MYSQL/orm_b_group/, ключ файла - md5(sql). Из кеша приходит ArrayResult, не "живой" DB Result - для fetch() обычно без разницы.

  1. Добавьте "cache" => ["ttl" => 3600] к повторяющемуся getList на staging.
  2. Обновите страницу дважды и откройте /bitrix/managed_cache/MYSQL/ - появится orm_b_*.
  3. Сравните slow log или SqlTracker: на втором хите SQL к таблице не уходит.
  4. Измените запись через GroupTable::update() и зафиксируйте ttl под частоту правок: справочник раз в неделю - 86400, оперативные данные - 300-600.

Делайте: кешируйте только стабильные справочники и каталоги с редкими правками. Не делайте: не ставьте ttl 86400 на данные, которые меняются каждый час без автосброса через ORM.

Настройте cache_joins для Reference и JOIN-выборок

Workflow cache_joins для JOIN-выборок D7 ORM с Reference

Выборки с JOIN и Reference по умолчанию не кешируются. Нужен cache_joins => true. Типичная ошибка на практике: ttl есть, JOIN есть, а SQL идёт каждый раз - забыли cache_joins. Или cache_joins включили, а связанное поле устарело после правки соседней таблицы.

$result = CityTable::getList([
    'select'  => ['ID', 'NAME', 'COUNTRY_NAME' => 'COUNTRY.NAME'],
    'runtime' => [
        new Reference(
            'COUNTRY',
            CountryTable::class,
            Join::on('this.COUNTRY_ID', 'ref.ID')
        ),
    ],
    'cache' => [
        'ttl' => 3600,
        'cache_joins' => true,
    ],
]);

Подробнее про Reference и Join - в гайде по связям D7 ORM (B79). Здесь важно правило: cache_joins => true только когда уверены, что связанные таблицы инвалидируются вместе или ttl приемлем.

Делайте: включайте cache_joins для стабильных JOIN-справочников. Не делайте: не кешируйте JOIN с часто меняющимися полями без короткого ttl или cleanCache() на обеих таблицах.

Сбросьте кеш через cleanCache() после raw SQL и импорта

DataManager автоматически сбрасывает ORM-кеш таблицы при add(), update(), delete(). Принудительный сброс всей выборки сущности:

CityTable::cleanCache();
// эквивалент:
CityTable::getEntity()->cleanCache();

Автосброс не сработает при прямом SQL, legacy CIBlockElement::Update, нестандартном addMulti() или импорте в обход Table. Тогда CityTable::cleanCache() один раз - свежие данные без полной очистки из B20. Workflow: импорт → cleanCache() → getList с cache → витрина обновлена.

Делайте: вешайте cleanCache() в конец скрипта импорта или агента. Не делайте: не полагайтесь на автосброс, если правка шла мимо DataManager.

Проверьте cache_flags в .settings.php, если кеш "не пишется"

DevOps может ограничить TTL таблицы глобально. В /bitrix/.settings.php секция cache → cache_flags:

'cache_flags' => [
    'value' => [
        'b_group_min_ttl' => 60,
        'b_group_max_ttl' => 3600,
    ],
    'readonly' => false,
],

b_<table>_min_ttl - код не задаст TTL меньше минимума. b_<table>_max_ttl - верхняя граница; значение 0 полностью запрещает ORM-кеш этой таблицы, даже если в getList указан ttl 3600. Entity::getCacheTtl() учитывает эти лимиты - приоритет у maximum.

Если в коде cache есть, а каталога orm_b_* нет - первым делом проверьте cache_flags и readonly. Для отладки "почему не кешируется" смотрите логирование через Logger (B84), а не только var_dump в шаблоне.

Делайте: согласуйте ttl в коде с лимитами на staging перед prod. Не делайте: не отлаживайте "кеш не работает" часами, если max_ttl=0 выставлен в .settings.php.

Избегите ловушек: права, offset и персональные данные

На практике в реальном проекте ORM-кеш не добавляет в ключ пользователя и группы - персональные списки кешируйте с USER_ID в filter или без ORM cache. Offset-пагинация даёт отдельный файл кеша на страницу. Кешируется Result выборки, не EO_Collection - для готового массива после fetchAll() есть отдельный слой Data\Cache.

Делайте: кешируйте публичные справочники с одинаковым результатом для всех. Не делайте: не кешируйте "мои заказы" с ttl 3600 без учёта USER_ID в filter - получите чужие данные.

Пройдите чек-лист staging: правка → свежие данные

  1. Включите cache с ttl на тестовом getList и убедитесь в файлах orm_* на диске.
  2. Измените запись через Table::update() - витрина должна обновиться без cleanCache().
  3. Измените ту же таблицу через raw SQL - данные "залипнут"; вызовите cleanCache().
  4. Проверьте JOIN: без cache_joins SQL идёт каждый раз; с cache_joins - файлы кеша и актуальность связанных полей.
  5. Сверьте cache_flags: при max_ttl=0 файлов orm_* не будет - это ожидаемо.

Нужна помощь с кешем и производительностью модуля - обсудим задачу, примеры внедрений - в портфолио.

Автор: Максим Мольков, Senior-разработчик 1С-Битрикс.
Источники: выборка данных ORM Bitrix Framework, кеширование ManagedCache и cache_flags, урок D7: кеширование выборки getList, урок: cache_flags в .settings.php.

Частые вопросы

Чем ORM cache отличается от registerTag в компоненте?

ORM cache живёт в параметре cache у getList/getRow и кеширует результат SQL-запроса к таблице DataManager. registerTag в компоненте помечает HTML-блок тегами iblock_* и сбрасывается через clearByTag - это слой витрины, не выборки ORM. Подробнее - в гайде B66 по тегированному кешу.

Вызывается ли cleanCache при Table::update()?

Да. add(), update() и delete() через DataManager автоматически сбрасывают ORM-кеш этой таблицы. Ручной cleanCache() нужен после raw SQL, legacy-правок в обход ORM или нестандартного массового импорта.

Зачем cache_joins при JOIN в getList?

Без cache_joins => true выборки с Reference или JOIN не кешируются, даже если указан ttl. С cache_joins ключ учитывает связанные таблицы - включайте только когда готовы к инвалидации или короткому ttl. Детали JOIN - в B79.

Где на диске лежит кеш ORM-запросов?

В /bitrix/managed_cache/MYSQL/orm_<имя_таблицы>/, например orm_b_group. Имя файла - md5 от SQL. Это управляемый кеш, не путать с /bitrix/cache/ (неуправляемый компонентный).

Почему addMulti может не сбросить кеш?

Стандартный addMulti в DataManager участвует в автосбросе, но кастомные обёртки или HL-блоки с переопределённым addMulti без вызова родителя могут обойти сброс. После массовой загрузки безопаснее вызвать Table::cleanCache() явно.

Можно ли кешировать EO_Collection из getList?

Нет. ORM cache сохраняет Result выборки как ArrayResult - набор строк. Коллекции объектов с методами и замыканиями в этот механизм не попадают. Сохраняйте массив через fetchAll() или используйте отдельный слой Data\Cache для готовых структур.

Читайте также

Интеграции с 1С и API
1073 6 мин.

Как настроить регистрацию и личный кабинет покупателя на 1С-Битрикс?

Пошаговая настройка регистрации на сайте битрикс: Главный модуль, main.register, system.auth.form и sale.personal.section с историей заказов и 152-ФЗ.
Интеграции с 1С и API
941 6 мин.

Как настроить скидки и промокоды на 1С-Битрикс: правила корзины и купоны

Пошаговый гайд по скидкам в CMS-магазине: скидка на товар, правило корзины от суммы, купоны с лимитом, приоритеты без конфликтов и тестовый заказ. Не Bitrix24.
Интеграции с 1С и API
757 15 мин.

Что такое компонент в Битриксе и как он работает

Каждый разработчик, впервые столкнувшийся с Битриксом, проходит через своеобразный обряд посвящения. Вначале кажется, что это просто CMS, где можно поправить HTML в визуальном редакторе или дописать пару строк CSS. Но однажды наступает момент, когда нужно изменить логику вывода новостей, отфильтровать товары по хитрому свойству или добавить на страницу нечто совершенно новое. И тут он впервые слышит это слово — «компонент». Для многих этот момент становится стеной. Система, казавшаяся понятной, вдруг превращается в черный ящик, полный непонятных файлов и странных переменных. Но стоит лишь раз заглянуть под капот, как эта стена рассыпается, превращаясь в набор удивительно логичных и мощных строительных блоков. Понимание компонентов — это тот самый щелчок, после которого разработка на Битрикс из мучения превращается в творчество.

Эта статья — ваш проводник в мир компонентов «1С-Битрикс». Мы не будем сыпать сухими терминами из документации. Вместо этого мы совершим путешествие: от философии, заложенной в эту архитектуру, до мельчайших деталей её работы. Мы разберем компонент на атомы — его файлы, логику, шаблон, параметры — и соберем обратно, чтобы вы не просто знали, что это, но и глубоко понимали, почему это работает именно так. Это знание — ключ к эффективной и профессиональной разработке на Битрикс.

Интеграции с 1С и API
717 2 мин.

Установка Composer в 1С-Битрикс

Установка Composer в проекте на 1С-Битрикс требует учета особенностей платформы, чтобы обеспечить корректную работу и интеграцию с системой.