Разработка фильтрации с автоподсчетом количества товаров 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Разработка фильтрации с автоподсчетом количества товаров 1С-Битрикс
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • 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
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    747
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Разработка фильтрации с автоподсчётом количества товаров 1С-Битрикс

Стандартный компонент catalog.smart.filter в 1С-Битрикс считает количество товаров через отдельный SQL-запрос к b_iblock_element с полным пересчётом при каждом изменении параметров фильтра. При каталоге в 50 000+ SKU это даёт задержку 800–1500 мс на фильтрацию — пользователь видит «зависший» интерфейс. Задача усугубляется, если в каталоге используется торговый каталог (catalog модуль) с привязкой к b_catalog_price и множественными свойствами через b_iblock_element_property.

Как работает «умный фильтр» и где он ломается

Компонент bitrix:catalog.smart.filter при включённом параметре SHOW_PRODUCTS_COUNT выполняет агрегирующий запрос вида:

SELECT COUNT(DISTINCT BE.ID)
FROM b_iblock_element BE
INNER JOIN b_iblock_element_property BEP ON BE.ID = BEP.IBLOCK_ELEMENT_ID
WHERE BE.IBLOCK_ID = ? AND BE.ACTIVE = 'Y' AND BEP.IBLOCK_PROPERTY_ID = ? AND BEP.VALUE = ?

При десяти одновременно выбранных свойствах фильтра это превращается в цепочку JOIN-ов или подзапросов, которые MySQL выполняет без использования составных индексов. EXPLAIN показывает тип ALL или index вместо ref — полный перебор таблицы.

Вторая проблема — инвалидация кеша. Стандартный тег кеша bitrix:catalog сбрасывается при любом изменении любого элемента инфоблока, включая изменение остатков. Магазины с частыми обновлениями склада получают постоянный холодный старт фильтра.

Архитектура решения с автоподсчётом

Мы переносим подсчёт из SQL-агрегации в денормализованную таблицу счётчиков и строим AJAX-механику вокруг неё.

Структура денормализации:

Создаётся отдельная таблица catalog_filter_counts (или HighLoad-блок, если требуется UI в админке):

CREATE TABLE catalog_filter_counts (
    iblock_id    INT NOT NULL,
    prop_id      INT NOT NULL,
    prop_value   VARCHAR(255) NOT NULL,
    section_id   INT NOT NULL DEFAULT 0,
    cnt          INT NOT NULL DEFAULT 0,
    updated_at   TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_filter (iblock_id, section_id, prop_id, prop_value)
);

Счётчики пересчитываются через агент Битрикс (CAgent) по расписанию — раз в 5–15 минут, или через обработчик события OnAfterIBlockElementUpdate для критичных изменений.

AJAX-компонент фильтра:

Вместо стандартного smart.filter подключается кастомный компонент на основе bitrix:main.ui.filter, который при изменении чекбокса отправляет запрос на компонент-роутер:

// component.php
$filterState = $this->request->getPost('filter_state');
$counts = CatalogFilterCountsTable::getList([
    'filter' => [
        '=IBLOCK_ID' => $ibId,
        '=SECTION_ID' => $sectionId,
        '@PROP_VALUE' => $filterState['values'],
    ],
    'select' => ['PROP_ID', 'PROP_VALUE', 'CNT'],
])->fetchAll();

Ответ возвращается JSON-объектом, фронтенд обновляет счётчики в DOM без перезагрузки страницы.

Кеширование подсчётов

Денормализованная таблица сама по себе — уже кеш. Но для снижения нагрузки на БД при высоком трафике добавляется второй слой через Bitrix\Main\Data\Cache с тегом, привязанным к конкретному инфоблоку и разделу:

$cache = Cache::createInstance();
$cacheId = 'filter_counts_' . $ibId . '_' . $sectionId;
if ($cache->initCache(3600, $cacheId, '/catalog/filter/')) {
    $counts = $cache->getVars();
} else {
    $cache->startDataCache();
    $counts = /* запрос к БД */;
    $cache->endDataCache($counts);
}

Инвалидация происходит только при реальном изменении ассортимента, а не при каждом обновлении цены или остатка.

Кейс: интернет-магазин строительных материалов

Клиент — магазин с каталогом 80 000 SKU, 12 свойствами в фильтре (бренд, размер, цвет, материал и т.д.), интеграцией с 1С через d7 обменник. Стандартный smart.filter с SHOW_PRODUCTS_COUNT = Y давал среднее время ответа 2,3 с на страницах категорий. После каждого обмена с 1С (каждые 30 минут) кеш сбрасывался, и первые 5 минут сайт работал под нагрузкой без кеша.

Что сделали:

  • Выключили стандартный SHOW_PRODUCTS_COUNT
  • Реализовали денормализованную таблицу счётчиков с пересчётом через агент раз в 10 минут
  • Разработали AJAX-компонент на основе bitrix:catalog.section + кастомный bitrix:main.ui.filter
  • Добавили серверный кеш счётчиков с TTL 600 с, инвалидируемый только при смене ассортимента (не цен и остатков)

Результат: время ответа фильтра снизилось до 80–120 мс, нагрузка на MySQL в часы пик упала вдвое. Обмен с 1С перестал влиять на производительность фильтра.

Интеграция с торговым каталогом и множественными ценами

Отдельный случай — каталоги с несколькими типами цен (b_catalog_price) и фильтрацией по диапазону цен. Стандартный фильтр при этом добавляет JOIN к b_catalog_price с дополнительными условиями по CATALOG_GROUP_ID. Здесь мы реализуем отдельный счётчик диапазонов цен с квантованием (10 бакетов по диапазону) — это позволяет строить ползунок цены без выполнения MIN/MAX агрегации при каждом запросе.

Сроки и этапы

Разработка фильтра с автоподсчётом включает аудит текущей структуры инфоблока и свойств, проектирование схемы денормализации, разработку агента пересчёта и AJAX-компонента, настройку кеширования и нагрузочное тестирование.

Масштаб каталога Сложность фильтра Срок разработки
до 20 000 SKU до 8 свойств 3–5 дней
20 000–100 000 SKU до 15 свойств 5–10 дней
100 000+ SKU / HighLoad любая 10–20 дней

Нагрузочное тестирование проводится инструментами Apache Benchmark или wrk на тестовой копии продакшн-базы — без него результат непредсказуем.