Optimizing 1C-Bitrix Infoblock Queries: Speed Up Your Catalog
Real Problem: Slow Infoblock Queries
We often encounter projects where the Bitrix catalog slows down due to non-optimal infoblock queries. Typical scenario: a product listing page with 48 items takes 2-3 seconds to load, even when the MySQL server is not overloaded. The standard CIBlockElement::GetList with property filtering generates multiple JOINs, and with 100 products having 5 properties each, EXPLAIN shows scans of hundreds of thousands of rows. TTFB exceeds 1 second even on a VPS with 4 vCPUs. The platform 1C-Bitrix is one of the popular CMS for e-commerce, yet its infoblocks often become a bottleneck. In our practice, with over 50 optimized projects, 90% of problems are solved by migrating to D7 ORM and properly placing indexes. This reduces server resource costs and stays within budget without extra investment. We guarantee a 3-5x reduction in query time. This article is the result of our years of experience.
Why Standard Bitrix Queries Are Slow?
The old API CIBlockElement::GetList when using PROPERTY_* filter adds a JOIN for each property. If there are 5 properties in the filter — 5 JOINs. The query plan becomes non-optimal, especially when the b_iblock_element_property table contains millions of rows. Additionally, the arSelect parameter with "*" or without an explicit list forces the API to pull all fields, including long texts like PREVIEW_TEXT and DETAIL_TEXT. As a result, the data volume from the database increases by 3-5 times.
Another common mistake is the N+1 query problem. After fetching a list of items, developers often call CIBlockElement::GetProperty() for each product in a loop. For 48 products, that's 1 + 48 = 49 queries. Execution time grows linearly.
How to Implement Batch Fetching Without Regression?
Switching to \Bitrix\Iblock\ElementTable from D7 ORM gives full control over SQL. Each query can be verified using getQuery()->getSql() before execution. Example of an optimal query for a catalog page:
use Bitrix\Iblock\ElementTable; $result = ElementTable::getList([ 'select' => [ 'ID', 'NAME', 'CODE', 'PREVIEW_PICTURE', 'IBLOCK_SECTION_ID', ], 'filter' => [ '=IBLOCK_ID' => CATALOG_IBLOCK_ID, '=ACTIVE' => 'Y', '=IBLOCK_SECTION_ID' => $sectionId, ], 'order' => ['SORT' => 'ASC', 'ID' => 'ASC'], 'limit' => 24, 'offset' => $page * 24, 'cache' => ['ttl' => 3600], ]); Explicit select without properties — the query hits only b_iblock_element, no JOINs. If property values are needed for multiple products, we use batch fetching by IDs:
$ids = array_column($elements, 'ID'); $propsResult = \CIBlockElement::GetPropertyValuesArray( $ids, CATALOG_IBLOCK_ID, ['CODE' => ['BRAND', 'COLOR', 'SIZE']] ); This "fetch by ID in batches" pattern solves the N+1 problem. The official documentation on D7 ORM contains all the details. 1C-Bitrix Academy
Case Study from Our Practice: Construction Materials Catalog with 45,000 SKUs
We worked with a client — an online store of construction materials. The catalog contained 45,000 active items. A section page with 48 products loaded in 1.8 seconds without cache. MySQL slow query log revealed several issues:
-
CIBlockElement::GetListwithSELECT => "*"andPROPERTY_FILTERon 5 properties took 640 ms per query. - The "related products" block executed a separate query for each of the 6 items (N+1).
- The section tree query had no depth level limit.
We performed the following actions:
- Rewrote the main query to D7, leaving only 8 necessary fields.
- Replaced iterative property queries with batch fetching using
GetPropertyValuesArray. - Limited
DEPTH_LEVELin the section fetch and added tagged cache. - Created a composite index on
b_iblock_element:
ALTER TABLE b_iblock_element ADD INDEX idx_iblock_section_active_sort (IBLOCK_ID, IBLOCK_SECTION_ID, ACTIVE, SORT); Result: TTFB of the section page without cache dropped from 1.8 s to 380 ms, with cache — to 45 ms. The number of database queries decreased from 12 to 4. MySQL load reduced by 3 times, saving the client up to 30% on server costs. The client gained the ability to serve more visitors without increasing expenses.
Comparison of Old vs. New Approach
| Parameter | CIBlockElement::GetList | D7 ORM + Batches |
|---|---|---|
| JOIN count when filtering by 5 properties | 5 | 0 (if properties not in select) |
| SQL control | No | Full (getQuery()->getSql()) |
| N+1 risk | High | Eliminated by batch fetching |
| Caching | Only file-based | Tagged + data cache |
| Performance (example) | 640 ms | 80 ms |
D7 API is 3-5x faster for typical queries.
What's Included in the Optimization Work
We offer comprehensive infoblock query optimization turnkey. The work includes:
- Analysis of MySQL slow query log and Bitrix performance panel.
- Audit of all custom components for N+1 and non-optimal fetches.
- Rewriting critical queries to D7 ORM with explicit select and batch strategies.
- Adding necessary composite indexes and configuring tagged cache.
- Creating documentation for optimized queries for your team.
- Training developers on D7 and best practices.
More about our experience
We have been doing Bitrix development for over 10 years, certified by 1C-Bitrix. Successfully optimized catalogs for 20+ large projects with traffic from 10,000 visitors per day.Timelines and Pricing
| Stage | Duration |
|---|---|
| Query audit (slow log, Explain, Bitrix panel) | 1–2 days |
| Rework critical queries (D7, batching) | 3–7 days |
| Indexes and cache setup | 1–2 days |
| Documentation and training | 1 day |
Pricing is calculated individually based on catalog size and component count. Contact us for an evaluation of your project — it takes 2 days. Get a consultation on speeding up your catalog.

