Настройка индексов базы данных 1С-Битрикс
Запрос к каталогу на 50 000 товаров занимает 4 секунды вместо 40 миллисекунд. EXPLAIN показывает ALL вместо ref — таблица читается целиком. Это типичный сценарий Битрикс-сайта под нагрузкой, где индексы не добавлялись после роста данных или были удалены при обновлении схемы.
Ключевые таблицы Битрикс и их индексы
Структура хранения данных инфоблоков разбита на несколько таблиц:
-
b_iblock_element— основные записи элементов (поляACTIVE,IBLOCK_ID,CODE,XML_ID,DATE_ACTIVE_FROM) -
b_iblock_element_property— значения свойств типа строка/число -
b_iblock_property_enum— значения свойств-списков -
b_iblock_section— секции (разделы каталога) -
b_iblock_section_element— связь элемент—раздел
На боевом проекте b_iblock_element_property легко достигает 10–30 миллионов строк. Запрос фильтрации по двум свойствам без индекса — это full scan обеих таблиц.
Диагностика медленных запросов
Включить slow query log в MySQL/MariaDB:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
Битрикс поддерживает собственное профилирование через константу в dbconn.php:
define("DBDebug", true);
define("DBDebugToFile", true);
Лог пишется в bitrix/modules/main/tools/bx_sql.log. Но на продакшне это включать ненадолго — файл разрастается мгновенно.
Обязательные индексы для инфоблоков
Проверить наличие индексов:
SHOW INDEX FROM b_iblock_element;
SHOW INDEX FROM b_iblock_element_property;
Если отсутствует составной индекс по (IBLOCK_ID, ACTIVE, DATE_ACTIVE_FROM) в b_iblock_element — добавить:
ALTER TABLE b_iblock_element
ADD INDEX ix_ie_iblock_active_date (IBLOCK_ID, ACTIVE, DATE_ACTIVE_FROM);
Для фильтрации по свойствам через CIBlockElement::GetList с параметром PROPERTY_* критичен индекс в b_iblock_element_property:
ALTER TABLE b_iblock_element_property
ADD INDEX ix_iep_iblock_prop_val (IBLOCK_ID, IBLOCK_PROPERTY_ID, VALUE);
ALTER TABLE b_iblock_element_property
ADD INDEX ix_iep_element_prop (IBLOCK_ELEMENT_ID, IBLOCK_PROPERTY_ID);
Индексы для модуля поиска и хитов
Таблица b_search_content при активном поиске растёт быстро. Базовый индекс:
ALTER TABLE b_search_content
ADD INDEX ix_sc_module_item (MODULE_ID, ITEM_ID);
Таблица b_stat_phrase_date (модуль statistic) — частая причина медленных отчётов:
ALTER TABLE b_stat_phrase_date
ADD INDEX ix_spd_date_phrase (DATE1, PHRASE_ID);
Индексы для торгового каталога
Модуль catalog работает с таблицами b_catalog_price, b_catalog_product, b_catalog_store_product:
-- Поиск по цене в диапазоне
ALTER TABLE b_catalog_price
ADD INDEX ix_cp_catalog_price (CATALOG_GROUP_ID, PRICE, CURRENCY);
-- Остатки на складах
ALTER TABLE b_catalog_store_product
ADD INDEX ix_csp_product_store (PRODUCT_ID, STORE_ID);
Без второго индекса запрос остатков по всем складам при листинге каталога — O(n) по таблице складских остатков.
Статистика и очистка устаревшего
Битрикс-сайты с включённым модулем statistic накапливают миллионы строк в b_stat_* таблицах. Отдельная проблема — фрагментация индексов. После массовых удалений через «Очистку статистики» в административной панели индексы не перестраиваются автоматически.
Анализ фрагментации:
SELECT TABLE_NAME,
ROUND(DATA_FREE/1024/1024, 2) AS free_mb,
ROUND(DATA_LENGTH/1024/1024, 2) AS data_mb
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'bitrix_db'
AND DATA_FREE > 10485760
ORDER BY DATA_FREE DESC;
Перестройка индексов таблицы без блокировки (MySQL 5.6+):
ALTER TABLE b_iblock_element_property ENGINE=InnoDB;
-- или
OPTIMIZE TABLE b_iblock_element_property;
OPTIMIZE TABLE на InnoDB фактически делает ALTER TABLE ... ENGINE=InnoDB — полная перестройка. На таблице 5 ГБ займёт 10–20 минут с блокировкой. Для онлайн-перестройки — pt-online-schema-change из Percona Toolkit.
Автоматическое обслуживание индексов
В файл /bitrix/php_interface/init.php можно добавить агент, который раз в неделю запускает ANALYZE TABLE на критичных таблицах:
CAgent::AddAgent(
'MyAnalyzeTables();',
'main',
'N',
604800, // раз в неделю
'',
'Y'
);
function MyAnalyzeTables() {
global $DB;
$tables = ['b_iblock_element', 'b_iblock_element_property', 'b_catalog_price'];
foreach ($tables as $t) {
$DB->Query("ANALYZE TABLE {$t}");
}
return 'MyAnalyzeTables();';
}
ANALYZE TABLE обновляет статистику без блокировки на InnoDB — оптимизатор запросов получает актуальные данные о распределении значений.







