אופטימיזציה של הפילטר החכם לקטלוגים גדולים ב-1C-Bitrix

כשהקטלוג גדל, הפילטר החכם מתחיל להאט: עמודים נטענים תוך שניות, ולקוחות עוזבים למתחרים. אנחנו מייעלים את הפילטר של Bitrix עבור כמויות מוצרים גדולות, מאיצים שאילתות ומפחיתים את העומס על מסד הנתונים. הצוות שלנו מספק פרויקטים מסוג מפתח לתפעול, מאבחון ועד יישום, ומבטיח ביצועים יציבים גם כשהקטלוג מתרחב.
השירותים שאנו מציעים
מציג 1 מתוך 1כל 1626 השירותים
אופטימיזציה של הפילטר החכם לקטלוגים גדולים ב-1C-Bitrix
בינוני
~1-2 שבועות

הכישורים שלנו:

שאלות נפוצות

הפילטר החכם מתחיל לאבד ביצועים כאשר הקטלוג עולה על 5,000 פריטים. ב-50,000+ פריטים, זה יכול לקחת 5–15 שניות בבקשה הראשונה ו-1–3 שניות עם קאש. נשמע מוכר? כמפתחי ביטריקס עם ניסיון של 7+ שנים, נתקלנו בזה עשרות פעמים. עם 150+ פרויקטים מאחורינו, אנחנו מבטיחים תוצאות: הפחתת TTFB עד 200 אלפיות השנייה. זו לא בעיה של אלגוריתם — זו תוצאה של חישוב מחדש של מוני ערכים לכל מאפיין בכל בקשה. בפרויקט אמיתי עם 30 מאפיינים ו-50,000 מוצרים, זה אומר אלפי שאילתות מסד נתונים לכל קריאה בודדת.

איך הפילטר החכם עובד מתחת למכסה המנוע

רכיב ה-bitrix:catalog.smart.filter יוצר טופס עם טעינת תוצאות אסינכרונית דרך AJAX. צרכני המשאבים העיקריים הם שאילתות COUNT עבור כל ערך מאפיין. ללא אופטימיזציה, בקשה אחת לפילטר יכולה לגרום ליותר מ-200 פגיעות במסד הנתונים. ניתן לקרוא עוד על הפלטפורמה בוויקיפדיה.

איך לאבחן את הבעיה

השלב הראשון הוא מדידה, לא ניחושים. הפעל פרופילינג של 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 לחישוב מחדש של מספר המוצרים לכל ערך מאפיין עם הפילטר המופעל. להבנה מעמיקה של אינדוקסים ב-MySQL, אני ממליץ על התיעוד.

למה אינדוקסים הם קריטיים

השיפור המשמעותי ביותר ללא שינויי קוד הוא אינדוקסים נכונים. הפילטר החכם עושה שימוש נרחב בטבלאות // В начале скрипта 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)); (מאפיינים פשוטים) ו-b_iblock_element_prop_s* (מאפיינים מרובים).

-- Проверка существующих индексов
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 ללא כל שינוי בקוד. השווה בין גישות:

גישה זמן בקשה ראשונה זמן קאש מורכבות
ללא אופטימיזציה 8–15 שניות 2–3 שניות —
אינדוקסים בלבד 1–2 שניות 0.5 שניות נמוכה
אינדוקסים + טעינה עצלה 0.2 שניות (TTFB) 0.3 שניות (מונים) בינונית
אינדוקסים + צבירה מוקדמת 0.15 שניות 0.15 שניות גבוהה

הערה: צבירה מוקדמת נותנת רווח של פי 50 בהשוואה לשאילתות חיות בקטלוג של 150,000 פריטים.

איך להגדיר קאש לפילטר

$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', // ленивая загрузка счётчиков
]);

b_iblock_element_prop_m* — המונים נטענים דרך בקשת AJAX נפרדת לאחר רינדור העמוד. העמוד מגיב מהר, המונים מופיעים תוך 200–400 אלפיות השנייה.

קאש עם תגי invalidation

קאש אגרסיבי עם invalidation כאשר הקטלוג משתנה:

// Тег кеша привязан к инфоблоку
$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 דקות. המונים בממשק המשתמש נשלפים מהטבלה הזו — לא משאילתות חיות.

הפחתת מספר המאפיינים בפילטר

לעתים קרובות 30–40% מהמאפיינים בפילטר אף פעם לא בשימוש. נתח נתונים ממערכות אנליטיקה:

  • הגדר אירועי GTM על אינטראקציות עם כל בלוק פילטר
  • במשך 30 יום, קבע בלוקים בשימוש לעומת לא בשימוש
  • הסר בלוקים עם פחות מ-2% אינטראקציה

בפועל, לאחר ביקורת כזו, קטלוג עם 28 מאפיינים בפילטר מסיים עם 12–15. זמן יצירת העמוד יורד ב-35–60% ללא שינויים טכניים.

מהניסיון שלנו: מרקטפלייס עם 80,000 פריטים

מרקטפלייס לחומרי בניין. הפילטר הגיב ב-8–12 שניות בבקשה הראשונה, 2–3 שניות עם קאש. אינדקס הקאש אופס בכל פעם שספק שינה מחיר (עשרות פעמים ביום).

הפתרון בשלושה שלבים:

  1. הוספנו אינדוקסים מורכבים על טבלאות המאפיינים — הזמן ירד ל-1.8 שניות ללא קאש
  2. צבירה מוקדמת של מונים דרך סוכן כל 20 דקות — מונים מהטבלה ב-5 אלפיות השנייה
  3. טעינה עצלה של מונים — הבייט הראשון של העמוד ב-180 אלפיות השנייה, מונים ב-300 אלפיות השנייה

תוצאה: מ-8–12 שניות ל-180 אלפיות השנייה TTFB, מונים ב-300 אלפיות השנייה.

מה כלול בעבודת האופטימיזציה?

  • ביקורת על תצורת הפילטר הנוכחית ופרופילינג של SQL
  • יצירה ואופטימיזציה של אינדוקסים לטבלאות המאפיינים
  • הגדרת קאש (מתויג, טעינה עצלה)
  • צבירה מוקדמת של מונים (במידת הצורך)
  • המלצות להפחתת מאפיינים לא בשימוש
  • תיעוד ליישום ותמיכה
  • ייעוץ עם הצוות שלך לפיתוח עתידי

לוח זמנים ואיך להתחיל

ביקורת, הוספת אינדוקסים והגדרת קאש — 1–2 ימי עסקים. אופטימיזציה מלאה עם צבירה מוקדמת, טעינה עצלה וביקורת מאפיינים לא בשימוש — 3–5 ימי עסקים.

נעריך את הפרויקט שלך תוך יום אחד. הזמן ביקורת פילטר — קבל תוכנית אופטימיזציה. צור קשר כדי לדון בפרטים. השאר בקשה לייעוץ — ננתח את הקטלוג שלך.