ביקורת ביצועי שאילתות SQL ב-Bitrix
באתר Bitrix טיפוסי בעל עומס גבוה, ה-CMS מייצר בין 200 ל-1000 שאילתות SQL לכל עמוד. רובן חוזרות על עצמן, מיותרות, או מכילות SELECT *. לפני שמשקיעים בשרת יקר יותר, כדאי להבין אילו שאילתות איטיות ומדוע. במשך 10 שנות עבודה עם Bitrix, ראינו שוב ושוב פרויקטים שבהם אינדקס חסר אחד או מטמון נעדר צרכו 70% ממשאבי מסד הנתונים.
אופטימיזציה של שאילתות SQL אינה פעולה חד-פעמית אלא תהליך מתמשך. הלקוחות שלנו משיגים עד 50% הפחתה בעומס השרת וזמני יצירת עמוד מהירים פי 2–5. לדוגמה, חנות מסחר אלקטרוני עם 50,000 פריטים בקטלוג הפחיתה את זמן טעינת העמוד מ-12 שניות ל-0.4 שניות על ידי הוספת אינדקס מורכב, וחסכה כ-2,400 דולר בחודש בעלויות שרת. אופטימיזציה כזו מחזירה את ההשקעה תוך 2–3 חודשים. בואו נראה כיצד לזהות ולחסל צווארי בקבוק.
כיצד לזהות שאילתות SQL איטיות
בצעו את השלבים הבאים:
- הפעילו את כלי מעקב ה-SQL של Bitrix בלוח הביצועים (
b_iblock_element_property) או הוסיפו רישום פרוגרמטי:
\Bitrix\Main\Diag\SqlTracker::getInstance()->start();
// ... ваш код ...
$tracker = \Bitrix\Main\Diag\SqlTracker::getInstance();
$tracker->stop();
foreach ($tracker->getQueries() as $query) {
echo $query->getSql() . ' — ' . $query->getTime() . 'ms' . PHP_EOL;
} -
נתחו את הכלי: חפשו שאילתות איטיות מ-50 אלפיות השנייה, כפילויות (אותה שאילתה שחוזרת 10–50 פעמים בעמוד), ושאילתות ללא
/bitrix/admin/perfmon_panel.phpעל טבלאות גדולות. -
בנוסף, הפעילו את
\Bitrix\Main\Diag\SqlTracker::getInstance()->start(); // ... ваш код ... $tracker = \Bitrix\Main\Diag\SqlTracker::getInstance(); $tracker->stop(); foreach ($tracker->getQueries() as $query) { echo $query->getSql() . ' — ' . $query->getTime() . 'ms' . PHP_EOL; }ב-MySQL/MariaDB (WHEREב-slow_query_log) — הוא מספק תמונה אמיתית תחת עומס ייצור.
מדוע אינדקסים קריטיים עבור Bitrix
long_query_time = 0.5 יכול להכיל בין 10,000 ל-1,000,000 שורות. שאילתה כמו my.cnf ללא אינדקס על b_iblock_element מבצעת סריקת טבלה מלאה. בדקו עם SELECT * FROM b_iblock_element WHERE IBLOCK_ID = 5 AND ACTIVE = 'Y' ORDER BY SORT — אם אתם רואים (IBLOCK_ID, ACTIVE, SORT) בעמודת EXPLAIN SELECT ..., האינדקס חסר.
Bitrix יוצר אינדקסים במהלך ההתקנה אך לא עבור שדות מוגדרי משתמש (טבלאות UTS כמו type). יש להוסיף אינדקסים על טבלאות אלה ידנית. מניסיוננו, אינדקסים נכונים מאיצים שאילתות ספציפיות פי 2–10.
— בהתבסס על תיעוד MySQL ושיטות עבודה מומלצות מאופטימיזציית אינדקסים ב-MySQL.
בחירת שדות מוגזמת
ALL כברירת מחדל מבצע LEFT JOIN עם b_uts_iblock_N_single ומחזיר עשרות שדות, כולל CIBlockElement::GetList() שיכולים להיות בגודל מגה-בייט. אם העמוד צריך רק b_iblock_element_iprop, DETAIL_TEXT ו-ID, ציינו NAME במפורש:
CIBlockElement::GetList(
['SORT' => 'ASC'],
['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'],
false,
['nPageSize' => 20],
['ID', 'NAME', 'PREVIEW_PICTURE']
);
זה מפחית את העומס ב-20–40%.
בעיית N+1 וכיצד לתקן אותה
התרחיש הקלאסי: אתם טוענים 20 פריטים, ואז בלולאה מביאים מאפיינים לכל אחד עם שאילתה נפרדת. זה 21 שאילתות במקום 1–2. ב-API הישן, זה נפתר עם PREVIEW_PICTURE; ב-D7, השתמשו ב-$select עם CIBlockElement::GetList( ['SORT' => 'ASC'], ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'], false, ['nPageSize' => 20], ['ID', 'NAME', 'PREVIEW_PICTURE'] ); . לאחר האופטימיזציה, מספר השאילתות יורד פי 3–5.
שאילתות חוזרות לאותם נתונים
הגדרות אתר, קבוצות משתמשים, סעיפי אינפובלוק — אלה נטענים שוב ושוב בכל עמוד. המטמון הסטנדרטי של Bitrix ($arSelectFields) אמור לטפל בזה, אבל אם המטמון מושבת או שהמטמון המתויג נפסל לעתים קרובות, השאילתות פוגעות במסד הנתונים. Bitrix ממליצה להשתמש במטמון מתויג.
מה נותן מטמון ברמת השאילתה
אם הנתונים משתנים פעם בשעה, אין צורך לפגוע במסד הנתונים בכל בקשה. השתמשו ב-fetchCollection() עם מטמון מתויג:
$cache = \Bitrix\Main\Data\Cache::createInstance();
$cacheId = 'catalog_top_' . $iblockId;
$cachePath = '/catalog/top/';
if ($cache->initCache(3600, $cacheId, $cachePath)) {
$data = $cache->getVars();
} elseif ($cache->startDataCache()) {
$tagCache = new \Bitrix\Main\Data\TaggedCache();
$tagCache->startTagCache($cachePath);
$data = /* ваш запрос */;
$tagCache->registerTag('iblock_id_' . $iblockId);
$tagCache->endTagCache();
$cache->endDataCache($data);
}כאשר כל פריט אינפובלוק משתנה, התגית נפסלת אוטומטית. מטמון מתויג פוסל פי 3–5 מהר יותר ממטמון רגיל.
אופטימיזציה באמצעות D7 ORM
D7 ORM מאפשר שליטה מדויקת בשאילתות. השוו:
// Плохо: загружает все поля, все свойства
$result = \Bitrix\Iblock\ElementTable::getList([
'filter' => ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'],
]);
// Лучше: только нужные поля, явный лимит, кеш
$result = \Bitrix\Iblock\ElementTable::getList([
'select' => ['ID', 'NAME', 'PREVIEW_PICTURE_ID'],
'filter' => ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'],
'order' => ['SORT' => 'ASC'],
'limit' => 20,
'offset' => 0,
'cache' => ['ttl' => 3600],
]);
הפרמטר fill() בשאילתות ORM מספק מטמון מובנה. D7 ORM מהיר פי 2–3 מה-API הישן לבחירות.
עבודה עם אינדקסים
הוספת אינדקסים חסרים היא התיקון המהיר ביותר עם ההשפעה הגבוהה ביותר. הנה טבלה של האינדקסים השימושיים ביותר:
| טבלה | אינדקס מומלץ | מתי נדרש |
|---|---|---|
BXCache |
\Bitrix\Main\Data\Cache |
כמעט תמיד |
$cache = \Bitrix\Main\Data\Cache::createInstance(); $cacheId = 'catalog_top_' . $iblockId; $cachePath = '/catalog/top/'; if ($cache->initCache(3600, $cacheId, $cachePath)) { $data = $cache->getVars(); } elseif ($cache->startDataCache()) { $tagCache = new \Bitrix\Main\Data\TaggedCache(); $tagCache->startTagCache($cachePath); $data = /* ваш запрос */; $tagCache->registerTag('iblock_id_' . $iblockId); $tagCache->endTagCache(); $cache->endDataCache($data); } |
// Плохо: загружает все поля, все свойства $result = \Bitrix\Iblock\ElementTable::getList([ 'filter' => ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'], ]); // Лучше: только нужные поля, явный лимит, кеш $result = \Bitrix\Iblock\ElementTable::getList([ 'select' => ['ID', 'NAME', 'PREVIEW_PICTURE_ID'], 'filter' => ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'], 'order' => ['SORT' => 'ASC'], 'limit' => 20, 'offset' => 0, 'cache' => ['ttl' => 3600], ]); |
כשמסננים לפי מאפיינים |
cache |
b_iblock_element |
אזור חשבון הלקוח |
(IBLOCK_ID, ACTIVE, SORT) |
b_iblock_element_property |
עגלה ותשלום |
(IBLOCK_PROPERTY_ID, VALUE) |
b_sale_order |
חיפוש בקטלוגים גדולים |
ניתן להוסיף אינדקס באמצעות SQL או דרך Bitrix ORM:
$connection = \Bitrix\Main\Application::getConnection();
$connection->queryExecute(
"ALTER TABLE b_iblock_element_property ADD INDEX ix_prop_val (IBLOCK_PROPERTY_ID, VALUE(64))"
);היזהרו עם (USER_ID, STATUS_ID, DATE_INSERT): שדות מחרוזת מתויגים לפי קידומת. עבור ערכים מספריים, שקלו עמודה וירטואלית. פרטים נוספים בערך הוויקיפדיה על אינדקסי מסדי נתונים.
בעיות אופייניות בפרויקטים
- בחברה אחת, לא הצליחו להבין מדוע העגלה איטית במשך 6 חודשים. האשם היה שאילתה ל-
b_sale_basketללא אינדקס על(ORDER_ID, FUSER_ID). הוספת האינדקס הורידה את הזמן מ-10 שניות ל-0.1 שניות. - פרויקט אחר: עמוד רשימת ההזמנות באדמין ביצע 10,000 שאילתות עקב N+1 ברכיב מותאם אישית. לאחר ריפקטורינג, זה ירד ל-50 שאילתות.
ציר זמן לעבודה
| משימה | היקף | השפעה צפויה |
|---|---|---|
| פרופיילינג, זיהוי 10 השאילתות המובילות | יום אחד | הבנת הבעיה |
| הוספת אינדקסים חסרים | 1–2 ימים | האצה פי 2–10 בשאילתות ספציפיות |
אופטימיזציה של b_search_content_stem ברכיבים |
2–3 ימים | הפחתת עומס ב-20–40% |
| תיקון N+1, הוספת מטמון | 3–5 ימים | הפחתת מספר השאילתות פי 3–5 |
| מקיף: אינדקסים + בחירה + מטמון + ORM | 1–2 שבועות | 500+ שאילתות לעמוד → 50–100 |
מה כלול
- ביקורת על שאילתות SQL קיימות וזיהוי צווארי בקבוק.
- תכנון ויישום אינדקסים, אופטימיזציה של בחירות.
- יישום מטמון ומעבר ל-D7 ORM.
- תיעוד השינויים והמלצות לניטור.
- הדרכה לצוות הפיתוח שלכם.
- אחריות ל-3 חודשים על תקינות האופטימיזציה.
עם 10 שנות ניסיון, הסמכות Bitrix, ויותר מ-200 פרויקטים מוצלחים, אנו מבטיחים איכות. כל יום של עומס גבוה עולה לעסק שלכם — האופטימיזציה מחזירה את עצמה תוך כמה חודשים. הביקורת שלנו מתחילה ב-1,500 דולר, והחיסכון השנתי האופייני עולה על 10,000 דולר.
צרו קשר לביקורת — ננתח את הפרויקט שלכם ונציע צעדים קונקרטיים. הזמינו אופטימיזציה מקיפה ותראו את ההבדל במהירות.

