Оптимизация умного фильтра для большого каталога 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Оптимизация умного фильтра для большого каталога 1С-Битрикс
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1238
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    844
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    582
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    749
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    981

Оптимизация умного фильтра для большого каталога 1С-Битрикс

Умный фильтр начинает деградировать при каталоге от 5 000 позиций. При 50 000+ он может отвечать 5–15 секунд на первый запрос и 1–3 секунды с кешем. Это не проблема алгоритма — это следствие того, что фильтр пересчитывает счётчики для каждого значения каждого свойства при каждом запросе. На реальном проекте с 30 свойствами и 50 000 товарами это тысячи запросов к БД за одно обращение.

Диагностика: где теряется время

Первый шаг — замер, а не угадывание. Включаем SQL-профилировщик:

// В начале скрипта
define('LOG_FILENAME', $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/log_filter.php');
$GLOBALS['DB']->ShowSqlStat = 'Y';

// После отработки компонента фильтра
$sqlLog = $GLOBALS['DB']->GetSqlTrack();
// Смотрим самые медленные запросы
usort($sqlLog, fn($a, $b) => $b['time'] <=> $a['time']);
var_dump(array_slice($sqlLog, 0, 10));

Типичная картина: 80% времени уходит на COUNT-запросы для пересчёта количества товаров по каждому значению свойства при применённом фильтре.

Индексы для ускорения фильтра

Наиболее значимое улучшение без изменения кода — правильные индексы. Умный фильтр активно использует таблицы b_iblock_element_prop_s* (простые свойства) и b_iblock_element_prop_m* (множественные):

-- Проверка существующих индексов
SHOW INDEX FROM b_iblock_element_prop_s15; -- 15 = ID инфоблока

-- Добавление составного индекса для фильтрации
CREATE INDEX idx_filter_prop ON b_iblock_element_prop_s15 (IBLOCK_ELEMENT_ID, PROPERTY_186, PROPERTY_187);

-- Для таблицы множественных свойств
CREATE INDEX idx_mult_prop ON b_iblock_element_property
    (IBLOCK_ELEMENT_ID, IBLOCK_PROPERTY_ID, VALUE_ENUM, VALUE_NUM);

После добавления индексов время ответа на каталоге 30 000 позиций снижается в 2–4 раза без изменения кода.

Параметры кеширования умного фильтра

$APPLICATION->IncludeComponent('bitrix:catalog.smart.filter', 'my_filter', [
    'IBLOCK_ID'         => 15,
    'SMART_FILTER'      => 'Y',
    'CACHE_TYPE'        => 'A',    // авто
    'CACHE_TIME'        => 3600,   // 1 час
    'CACHE_GROUPS'      => 'N',    // не разделять кеш по группам пользователей
    'LAZY_LOAD'         => 'Y',    // ленивая загрузка счётчиков
]);

LAZY_LOAD = 'Y' — счётчики загружаются отдельным AJAX-запросом после отрисовки страницы. Страница отвечает быстро, счётчики появляются через 200–400 мс.

Кеш тегами с инвалидацией

Агрессивное кеширование с инвалидацией при изменении каталога:

// Тег кеша привязан к инфоблоку
$taggedCache = \Bitrix\Main\Data\TaggedCache::instance();
$taggedCache->startTagCache('/catalog/filter/');

// Выполняем работу фильтра
// ...

$taggedCache->registerTag('iblock_id_' . CATALOG_IBLOCK_ID);
$taggedCache->endTagCache();

// При изменении элементов инфоблока — автоинвалидация:
// AddEventHandler('iblock', 'OnAfterIBlockElementUpdate', function($id, $fields) {
//     \Bitrix\Main\Data\TaggedCache::instance()->clearByTag('iblock_id_' . $fields['IBLOCK_ID']);
// });

Пред-агрегация счётчиков

Для каталогов 100 000+ позиций — предварительная агрегация в отдельную таблицу через агент:

// Таблица для хранения предагрегированных данных
// CREATE TABLE b_custom_filter_counts (
//     iblock_id INT, property_code VARCHAR(50),
//     property_value VARCHAR(255), cnt INT,
//     updated_at DATETIME,
//     PRIMARY KEY (iblock_id, property_code, property_value(100))
// );

class FilterCountsAgent
{
    public static function recalculate(): string
    {
        $iblockId = CATALOG_IBLOCK_ID;
        $propertyCodes = ['BRAND', 'MATERIAL', 'COUNTRY'];

        foreach ($propertyCodes as $code) {
            // Подсчёт через прямой SQL
            $sql = "
                INSERT INTO b_custom_filter_counts
                    (iblock_id, property_code, property_value, cnt, updated_at)
                SELECT
                    e.IBLOCK_ID,
                    p.CODE,
                    pv.VALUE,
                    COUNT(DISTINCT e.ID),
                    NOW()
                FROM b_iblock_element e
                INNER JOIN b_iblock_element_property ep ON ep.IBLOCK_ELEMENT_ID = e.ID
                INNER JOIN b_iblock_property p ON p.ID = ep.IBLOCK_PROPERTY_ID
                INNER JOIN b_iblock_property_enum pv ON pv.ID = ep.VALUE_ENUM
                WHERE e.IBLOCK_ID = {$iblockId}
                  AND e.ACTIVE = 'Y'
                  AND p.CODE = '{$code}'
                GROUP BY e.IBLOCK_ID, p.CODE, pv.VALUE
                ON DUPLICATE KEY UPDATE cnt = VALUES(cnt), updated_at = VALUES(updated_at)
            ";

            \Bitrix\Main\Application::getConnection()->query($sql);
        }

        return 'FilterCountsAgent::recalculate();';
    }
}

Агент запускается каждые 15–30 минут. Счётчики в UI берутся из этой таблицы — не из live-запросов.

Уменьшение количества свойств в фильтре

Часто 30–40% свойств в фильтре никогда не используются. Анализ данных из систем аналитики:

  • Подключить события GTM на взаимодействие с каждым блоком фильтра
  • За 30 дней определить используемые vs неиспользуемые блоки
  • Убрать из фильтра блоки с менее чем 2% взаимодействий

На практике после такого аудита каталог с 28 свойствами в фильтре оставляет 12–15. Время генерации страницы снижается на 35–60% без технических изменений.

Кейс: маркетплейс с 80 000 позиций

Маркетплейс стройматериалов. Фильтр отвечал 8–12 секунд на первый запрос, 2–3 с — с кешем. Индекс кеша сбрасывался при каждой смене цены поставщиком (десятки раз в день).

Решение в три этапа:

  1. Добавлены составные индексы на таблицы свойств — время 1,8 с без кеша
  2. Пред-агрегация счётчиков через агент каждые 20 минут — счётчики из таблицы за 5 мс
  3. Lazy load счётчиков — первый байт страницы через 180 мс, счётчики через 300 мс

Итого: с 8–12 с до 180 мс TTFB, счётчики за 300 мс.

Сроки выполнения

Аудит, добавление индексов и настройка кеширования — 1–2 рабочих дня. Полная оптимизация с пред-агрегацией, lazy load и аудитом используемых свойств — 3–5 рабочих дней.