ראינו ממקור ראשון כיצד רכיב catalog.smart.filter סטנדרטי ב-1C-Bitrix הופך ניווט בקטלוג עם יותר מ-50,000 פריטים לסיוט. כל לחיצה על תיבת סימון מפעילה שאילתת SQL נפרדת מול b_iblock_element עם ספירה מלאה מחדש — משתמשים ממתינים 800–1500 אלפיות השנייה לכל שינוי. הממשק נראה קפוא, והם עוזבים. הבעיה מחמירה כאשר הקטלוג משתמש במודול catalog עם חיבורי b_catalog_price ומספר מאפיינים דרך b_iblock_element_property. כתוצאה מכך, הסינון הופך לצוואר בקבוק, וכל החלפת 1C מאפסת את המטמון, מה שגורם לזמן השבתה נוסף.
הפתרון הטיפוסי — הפעלת SHOW_PRODUCTS_COUNT ברכיב — רק מחמיר את המצב: כל בקשה מבצעת שאילתת צבירה יקרה. אנו נוקטים בגישה שונה: מעבירים את הספירה לטבלה מנורמלת ובונים סביבה מנגנון AJAX. זה מניב האצה של פי 10–15 וחיסכון משמעותי במשאבי השרת.
מדוע הפילטר החכם הסטנדרטי מפגר?
רכיב 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 מבצע ללא שימוש באינדקסים מורכבים. 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 = ? מציג סוג EXPLAIN או ALL במקום index — סריקת טבלה מלאה.
הבעיה השנייה היא פסילת מטמון. תג המטמון הסטנדרטי ref מתאפס על כל שינוי בכל רכיב בלוק מידע, כולל עדכוני מלאי. חנויות עם עדכוני מחסן תכופים חוות התחלות קרות קבועות של הפילטר.
כיצד אנו פותרים את בעיית הספירה האוטומטית?
אנו מעבירים את הספירה מצבירת SQL לטבלת מונים מנורמלת ובונים סביבה מנגנון AJAX. גישה מוכחת זו נותנת האצה של פי 10–15 לעומת הרכיב הסטנדרטי.
מבנה הנורמליזציה: אנו יוצרים טבלה נפרדת bitrix:catalog (או בלוק HighLoad אם יש צורך בממשק ניהול):
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)
);המונים מחושבים מחדש באמצעות סוכן Bitrix (catalog_filter_counts) בלוח זמנים — כל 5–15 דקות, או דרך אירוע 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) ); לשינויים קריטיים.
רכיב סינון AJAX:
במקום CAgent הסטנדרטי, אנו מצמידים רכיב מותאם אישית המבוסס על OnAfterIBlockElementUpdate ששולח בקשה לרכיב נתב כאשר תיבת סימון משתנה:
// 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 ללא טעינת עמוד מחדש.
מה נותנים לנו מונים מנורמלים?
הטבלה המנורמלת עצמה היא כבר מטמון. אבל כדי להפחית את העומס על מסד הנתונים בתנועה גבוהה, אנו מוסיפים שכבה שנייה באמצעות smart.filter עם תג המקושר לבלוק מידע ולמקטע ספציפיים:
$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 פריטים, 12 מאפייני סינון (מותג, גודל, צבע, חומר וכו'), ואינטגרציית 1C דרך החלפת 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(); הסטנדרטי עם Bitrix\Main\Data\Cache נתן זמן תגובה ממוצע של 2.3 שניות בעמודי קטגוריה. לאחר כל החלפת 1C (כל 30 דקות), המטמון נוקה, וב-5 הדקות הראשונות האתר עבד תחת עומס ללא מטמון.
הפתרונות שיושמו:
- ביטלנו את
$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); }הסטנדרטי - יישמנו טבלת מונים מנורמלת עם חישוב מחדש דרך סוכן כל 10 דקות
- פיתחנו רכיב AJAX המבוסס על
d7+smart.filterמותאם אישית - הוספנו מטמון מונים בצד השרת עם TTL של 600 שניות, שנפסל רק על שינויי מבחר (לא מחירים או מלאי)
תוצאות: זמן תגובת הפילטר ירד ל-80–120 אלפיות השנייה — פי 20 מהר יותר מהגישה הסטנדרטית. עומס MySQL בשעות השיא ירד בחצי. החלפת 1C הפסיקה להשפיע על ביצועי הפילטר. החיסכון במשאבי השרת היה משמעותי, וצמיחת ההמרות הוסיפה עוד 30% להכנסות.
אינטגרציה עם קטלוג מסחר ומספר מחירים
מקרה מיוחד הוא קטלוגים עם מספר סוגי מחירים (SHOW_PRODUCTS_COUNT = Y) וסינון טווחי מחירים. הפילטר הסטנדרטי מוסיף JOIN ל-SHOW_PRODUCTS_COUNT עם תנאים נוספים על bitrix:catalog.section. כאן אנו מיישמים מונה טווחי מחירים נפרד עם קוונטיזציה (10 דליים לכל טווח) — זה מאפשר בניית מחוון מחירים ללא הרצת צבירת bitrix:main.ui.filter בכל בקשה.
מה כלול בעבודה ליצירת פילטר
- ביקורת המבנה הנוכחי — ניתוח בלוקי מידע, מאפיינים, נפח נתונים וביצועי הפילטר הנוכחיים.
- עיצוב סכמת הנורמליזציה — קביעת הרכב טבלת המונים, אינדקסים ולוחות זמנים של סוכנים.
- פיתוח רכיב — יצירת פילטר AJAX מותאם אישית המבוסס על
b_catalog_priceעם מטמון בצד השרת. - בדיקות עומס — אימות על עותק בדיקה של מסד הנתונים היצרני באמצעות Apache Benchmark או wrk.
- אינטגרציה עם החלפת 1C הקיימת — הגדרת פסילת מונים עם הגעת נתונים חדשים.
- תיעוד והדרכה — מסירת קוד מקור, תיאורי סוכנים, הוראות להוספת מאפיינים חדשים.
לוחות זמנים ושלבים
פיתוח פילטר עם ספירה אוטומטית כולל ביקורת מבנה בלוק המידע והמאפיינים הנוכחי, עיצוב סכמת הנורמליזציה, פיתוח סוכן החישוב מחדש ורכיב AJAX, הגדרת מטמון ובדיקות עומס. אנו מבטיחים שקיפות בכל שלב. לוחות הזמנים המשוערים תלויים בגודל הקטלוג ובמורכבותו; צרו קשר לקבלת הערכה מדויקת.
| היקף הקטלוג | מורכבות הפילטר | זמן פיתוח |
|---|---|---|
| עד 20,000 פריטים | עד 8 מאפיינים | 3–5 ימים |
| 20,000–100,000 פריטים | עד 15 מאפיינים | 5–10 ימים |
| 100,000+ פריטים / HighLoad | כל | 10–20 ימים |
בדיקות עומס מבוצעות עם Apache Benchmark או wrk על עותק בדיקה של מסד הנתונים היצרני — בלעדיהן, התוצאות בלתי צפויות.
השוואת גישות: סטנדרטית מול שלנו
| מאפיין | smart.filter סטנדרטי | הפתרון שלנו |
|---|---|---|
| זמן תגובה ב-80,000 פריטים | 2.3 שניות | 80–120 אלפיות השנייה |
| תלות בהחלפת 1C | איפוס מטמון מלא | עובד באופן עצמאי |
| אינדקסים בשימוש | אין (סריקה מלאה) | אינדקסים מורכבים (ref) |
| אפשרויות התאמה אישית | מוגבלות | מלאות |
במשך יותר מ-5 שנות עבודה, השלמנו יותר מ-50 פרויקטים של אופטימיזציית סינון ב-Bitrix. אם הקטלוג שלכם סובל מפיגור, פנו אלינו לייעוץ והערכת פרויקט. הזמינו פיתוח, ונמצא פתרון המותאם לנפח הנתונים שלכם.
לפי התיעוד הרשמי של 1C-Bitrix: שימוש באינדקסים מותאמים אישית בטבלאות מאפיינים מפחית את זמן ביצוע השאילתות בסדר גודל.
מידע נוסף על אינדקסים במסדי נתונים ניתן למצוא במאמר אינדקס (מסד נתונים).

