Setting up 1C-Bitrix database indexes

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Database Index Configuration in 1C-Bitrix

A query to a catalog of 50,000 products takes 4 seconds instead of 40 milliseconds. EXPLAIN shows ALL instead of ref — the table is read entirely. This is typical scenario for Bitrix site under load, where indexes weren't added after data growth or were deleted on schema update.

Key Bitrix Tables and Their Indexes

Data storage structure of infoblocks is split across multiple tables:

  • b_iblock_element — main element records (fields ACTIVE, IBLOCK_ID, CODE, XML_ID, DATE_ACTIVE_FROM)
  • b_iblock_element_property — property values of string/number type
  • b_iblock_property_enum — list property values
  • b_iblock_section — sections (catalog categories)
  • b_iblock_section_element — element-section relationship

On production project b_iblock_element_property easily reaches 10–30 million rows. Filtering query by two properties without index — full scan of both tables.

Diagnosing Slow Queries

Enable slow query log in 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';

Bitrix supports its own profiling via constant in dbconn.php:

define("DBDebug", true);
define("DBDebugToFile", true);

Log writes to bitrix/modules/main/tools/bx_sql.log. But on production enable briefly — file grows instantly.

Mandatory Indexes for Infoblocks

Check index presence:

SHOW INDEX FROM b_iblock_element;
SHOW INDEX FROM b_iblock_element_property;

If missing composite index on (IBLOCK_ID, ACTIVE, DATE_ACTIVE_FROM) in b_iblock_element — add:

ALTER TABLE b_iblock_element
ADD INDEX ix_ie_iblock_active_date (IBLOCK_ID, ACTIVE, DATE_ACTIVE_FROM);

For property filtering via CIBlockElement::GetList with PROPERTY_* parameter, critical index in 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);

Indexes for Search and Hit Modules

The b_search_content table grows quickly with active search. Basic index:

ALTER TABLE b_search_content
ADD INDEX ix_sc_module_item (MODULE_ID, ITEM_ID);

The b_stat_phrase_date table (module statistic) — common reason for slow reports:

ALTER TABLE b_stat_phrase_date
ADD INDEX ix_spd_date_phrase (DATE1, PHRASE_ID);

Indexes for Catalog Module

The catalog module works with b_catalog_price, b_catalog_product, b_catalog_store_product tables:

-- Search by price range
ALTER TABLE b_catalog_price
ADD INDEX ix_cp_catalog_price (CATALOG_GROUP_ID, PRICE, CURRENCY);

-- Stock levels on warehouses
ALTER TABLE b_catalog_store_product
ADD INDEX ix_csp_product_store (PRODUCT_ID, STORE_ID);

Without second index, stock query across all warehouses on catalog listing — O(n) on warehouse stock table.

Statistics and Cleanup of Outdated Data

Bitrix sites with enabled statistic module accumulate millions of rows in b_stat_* tables. Separate problem — index fragmentation. After bulk deletes via "Clear Statistics" in admin panel, indexes don't rebuild automatically.

Analyze fragmentation:

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;

Rebuild indexes without locking (MySQL 5.6+):

ALTER TABLE b_iblock_element_property ENGINE=InnoDB;
-- or
OPTIMIZE TABLE b_iblock_element_property;

OPTIMIZE TABLE on InnoDB actually does ALTER TABLE ... ENGINE=InnoDB — full rebuild. On 5 GB table takes 10–20 minutes with locking. For online rebuild — pt-online-schema-change from Percona Toolkit.

Automatic Index Maintenance

Add to /bitrix/php_interface/init.php agent running ANALYZE TABLE weekly on critical tables:

CAgent::AddAgent(
    'MyAnalyzeTables();',
    'main',
    'N',
    604800, // weekly
    '',
    '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 updates statistics without locking on InnoDB — query optimizer gets current data on value distribution.