-10%Переходите к нам от другого подрядчика — дадим скидку на первый этап работ

Оптимизация базы данных MySQL для 1С-Битрикс

Оптимизация базы данных MySQL для 1С-Битрикс: индексы, медленные запросы, настройка MariaDB, буфер InnoDB и обслуживание больших таблиц

Каталог в час пик открывается всё дольше, панель хостинга показывает загрузку процессора базой под потолок, а после ночного обмена с 1С сайт вообще «залипает» на минуты. Разработчик первым делом смотрит на кэш и фронтенд — и часто зря: узкое место сидит глубже, в самой базе данных. Медленные запросы без индексов, распухшие таблицы свойств и заказов, дефолтный конфиг MySQL, в котором буфер InnoDB меньше базы, — вот что реально держит магазин за горло под нагрузкой. И лечится это не «добавить памяти», а прицельной работой с БД.

Ниже — системный разбор оптимизации MySQL и MariaDB для 1С-Битрикс: как найти медленные запросы (slow query log, монитор производительности, EXPLAIN), когда и какие ставить индексы (в том числе свои — на свойства инфоблоков), как настроить сервер (innodb_buffer_pool_size, временные таблицы, соединения), что делать с большими таблицами и как их обслуживать, чистить и архивировать. Это выжимка из наших работ по ускорению интернет-магазинов на 1С-Битрикс — без тюнинга вслепую и мифических «волшебных» значений конфига.

Коротко

  • Сначала измерение: slow query log, «Монитор производительности» Битрикса и отладочная панель показывают, какие запросы тормозят.
  • Каждый тяжёлый запрос разбирают через EXPLAIN; чаще всего лечится индексом — иногда своим, на колонку свойства или пользовательского поля.
  • Индексы не бесплатны: лишние замедляют запись и обмен с 1С, поэтому индексируют то, по чему реально фильтруют и сортируют.
  • Движок для Битрикса — InnoDB; ключевая настройка памяти — innodb_buffer_pool_size под размер «горячих» данных.
  • Большие таблицы (свойства, заказы, логи, статистика, поиск) обслуживают, чистят и архивируют; кэш Битрикса и настройки БД дополняют друг друга, а не заменяют.

Как база данных влияет на скорость магазина

Каждая страница магазина на 1С-Битрикс — это набор SQL-запросов к базе. Список каталога выбирает элементы инфоблока и их свойства, фильтр обращается к фасетному индексу, карточка тянет предложения и остатки, корзина и заказ пишут и читают свои таблицы. Пока данных немного и запросы попадают в индексы, база отвечает за миллисекунды и остаётся невидимой. Но стоит каталогу вырасти, а запросу — начать сканировать таблицу целиком, как база из «невидимого помощника» превращается в главный тормоз страницы.

Важно понимать, что нагрузка на базу растёт нелинейно к трафику. Один тяжёлый запрос без индекса на пустом сайте отработает быстро, потому что данных мало. Тот же запрос на большом каталоге и под сотней параллельных посетителей выстраивается в очередь: пока один сканирует таблицу, остальные ждут, процессор базы упирается в потолок, и время ответа растёт лавинообразно. Именно поэтому «на тесте было быстро, а на проде встало» — почти всегда история про базу и объём данных.

Оптимизация БД работает по двум направлениям сразу. Первое — сократить число обращений к базе: этим занимается кэш Битрикса, который отдаёт готовый результат, не доходя до SQL. Второе — ускорить те запросы, которые всё же доходят: первая сборка страницы, персональные некэшируемые данные, обмен с 1С. Кэш убирает массу повторной работы, но не отменяет необходимость держать базу в порядке — иначе каждая «холодная» сборка и каждый обмен будут больно бить по скорости.

База и «зелёные» метрики

Скорость базы напрямую влияет на время генерации страницы на сервере, а значит на TTFB — время до первого байта, фундамент под метриками Core Web Vitals. Медленный запрос удлиняет генерацию, TTFB растёт, LCP проседает. Поэтому работа с БД — не отдельная «серверная» задача в вакууме, а часть той же цепочки, что кэш и фронтенд. Как метрики складываются в общую картину скорости магазина, мы разбираем в материале про Core Web Vitals для интернет-магазина.

Где БД становится узким местом: общая карта

Прежде чем чинить, полезно уложить в голове карту типичных узких мест базы в магазине на Битриксе. Они повторяются из проекта в проект, и знание карты сразу подсказывает, где искать.

Дальше в статье мы пройдём по этой карте сверху вниз: сначала научимся находить конкретные медленные запросы, потом разберём индексы и настройки сервера, затем большие таблицы, их обслуживание и архивацию, и в конце — highload-инструменты вроде партиционирования и репликации, которые нужны не всем.

Правило номер один: не трогайте конфиг, пока не измерили. «Поднять буфер и добавить памяти» помогает, только если узкое место действительно в памяти. Если тормозит один запрос без индекса, никакой буфер его не спасёт — нужен индекс. Начинают всегда с диагностики, а не с тюнинга наугад.

Поиск медленных запросов: инструменты

Оптимизация начинается с ответа на вопрос «что именно тормозит». Отвечают на него три инструмента, и лучше пользоваться всеми тремя — они смотрят на проблему с разных сторон.

ИнструментЧто показываетКогда применять
Slow query log MySQL/MariaDBВсе запросы дольше порога по всему сайтуНайти системно тяжёлые запросы за период
Монитор производительности БитриксаТяжёлые запросы, привязанные к страницамСвязать медленный SQL с конкретной страницей
Отладка и панель БитриксаЧисло и время SQL на одной страницеТочечная диагностика конкретного URL
EXPLAINПлан выполнения одного запросаПонять, почему запрос медленный, и как чинить

Логика связки простая. Slow query log и монитор дают список подозреваемых — какие запросы и на каких страницах тяжелее всего. Отладочная панель помогает воспроизвести проблему на конкретном URL и увидеть общее число запросов (часто оказывается, что их не десятки, а сотни — привет, N+1). А EXPLAIN отвечает на вопрос почему: сканирует ли запрос таблицу целиком, использует ли индекс, создаёт ли временную таблицу. Дальше — точечное лечение.

Slow query log: включение и анализ

Журнал медленных запросов — штатная возможность MySQL и MariaDB: сервер сам пишет в файл каждый запрос, который выполнялся дольше заданного порога. Это лучший способ увидеть системную картину «что тормозит по всему сайту за сутки», а не только на той странице, которую вы открыли. Включается в конфиге сервера (обычно секция [mysqld] в my.cnf / my.ini).

[mysqld]
# Включить журнал медленных запросов
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log

# Порог: писать запросы дольше 1 секунды
long_query_time = 1

# Также логировать запросы, не использующие индексы
log_queries_not_using_indexes = 1

# (опционально) ограничить объём таких «безиндексных» записей в минуту
log_throttle_queries_not_using_indexes = 60

После включения журнал быстро накапливает записи, и читать его вручную неудобно. Для сводки применяют утилиты, которые группируют похожие запросы и показывают суммарное время: штатную mysqldumpslow или более подробную pt-query-digest из Percona Toolkit. Они выводят топ запросов по суммарной нагрузке — именно с верхушки этого списка и начинают оптимизацию, потому что она даёт максимальный эффект.

# Топ медленных запросов по среднему времени
mysqldumpslow -s t /var/log/mysql/slow.log | head -n 40

# Подробный разбор с группировкой (Percona Toolkit)
pt-query-digest /var/log/mysql/slow.log > slow-report.txt
Осторожно с порогом. Слишком большой long_query_time спрячет «средне-медленные» запросы, которые по отдельности терпимы, но выполняются тысячи раз и в сумме дают основную нагрузку. Слишком маленький — раздует лог и создаст лишнюю запись на диск. Разумно начать с порога около секунды, найти самые тяжёлые запросы, а потом при необходимости опускать порог, чтобы выловить «массовые» частые запросы.

Монитор производительности 1С-Битрикс

У Битрикса есть собственный инструмент, который смотрит на базу глазами приложения, — модуль «Монитор производительности» (perfmon). Его ценность в том, что он привязывает тяжёлые запросы к страницам сайта: вы видите не абстрактный SQL из лога, а «этот запрос выполняется на странице раздела каталога и занимает столько-то». Это резко сокращает путь от симптома к причине.

Монитор ведёт свою таблицу собранных запросов и умеет показывать самые тяжёлые, самые частые, запросы без индексов. Там же в разделе производительности есть общий тест конфигурации и «Панель производительности», которая оценивает скорость сервера, PHP и базы. Для разработчика это удобная отправная точка: включил сбор на период реальной нагрузки, посмотрел топ, пошёл разбирать конкретные запросы через EXPLAIN.

Помимо монитора, для точечной диагностики одной страницы включают режим отладки Битрикса — отладочная панель показывает число выполненных SQL-запросов и суммарное время работы базы на этом URL. Если на одной странице каталога база выполняет сотни запросов, это почти наверняка либо выключенный (или несрабатывающий) кэш, либо эффект N+1 в выборке свойств. Как навести порядок с кэшем компонентов и теговой инвалидацией, подробно разобрано в материале про кэширование в 1С-Битрикс — база и кэш всегда чинятся в связке.

EXPLAIN: читаем план запроса

Когда конкретный тяжёлый запрос найден, следующий шаг — понять, почему он медленный. Это делает команда EXPLAIN: она показывает план выполнения — как база собирается доставать данные, какие индексы использует и сколько строк рассчитывает просмотреть. Достаточно приписать EXPLAIN перед запросом.

EXPLAIN
SELECT E.ID, E.NAME
FROM b_iblock_element E
WHERE E.IBLOCK_ID = 21
  AND E.ACTIVE = 'Y'
  AND E.XML_ID = 'ABC-12345';

В выводе смотрят на несколько ключевых колонок. type показывает способ доступа: ALL — это полный скан таблицы (плохо на больших данных), ref/eq_ref/const — доступ по индексу (хорошо). key — какой индекс реально выбран (если NULL — индекс не используется). rows — оценка числа просматриваемых строк (чем меньше, тем лучше). В колонке Extra тревожные сигналы — Using filesort (сортировка без индекса) и Using temporary (создание временной таблицы).

Колонка EXPLAINХороший знакТревожный знак
typeconst, eq_ref, ref, rangeALL (полный скан таблицы)
keyиспользуется подходящий индексNULL — индекс не выбран
rowsнебольшое число строкчисло, близкое к размеру таблицы
ExtraUsing index (покрывающий индекс)Using filesort, Using temporary

Практический алгоритм: увидели type = ALL и большой rows на фильтрующей колонке — почти наверняка не хватает индекса. Увидели Using filesort на сортировке, которая идёт часто, — подумайте об индексе, покрывающем сортировку. Увидели Using temporary на группировке — возможно, поможет индекс или пересмотр запроса. В новых версиях есть ещё EXPLAIN ANALYZE, который реально выполняет запрос и показывает фактическое время по шагам, — это уже точная диагностика, а не только оценка.

Индексы: скан таблицы против индекса

Индекс — главный инструмент ускорения запросов, поэтому разберём его суть на пальцах. Без индекса, чтобы найти строки по условию, база вынуждена прочитать таблицу целиком и проверить каждую строку — это полный скан. На тысяче строк он незаметен, на миллионах — это секунды и загрузка диска. Индекс — это заранее построенная и отсортированная структура (в InnoDB — B-дерево), по которой база находит нужные строки почти мгновенно, не читая остальные, как оглавление книги вместо перелистывания всех страниц.

Разница нагляднее всего на схеме: слева запрос без индекса вынужден пройти всю таблицу, справа — прыгает по индексу сразу к нужным строкам.

Полный скан против доступа по индексу Без индекса: скан всей таблицы строка 1 строка 2 строка 3 строка 4 строка 5 строка 6 — найдено строка 7 строка 8 читаем все подряд С индексом: прыжок к строке индекс (B-дерево) нужная строка — сразу остальные не читаются минимум обращений к диску
Схема: без индекса база читает всю таблицу и проверяет каждую строку; с индексом она по B-дереву сразу переходит к нужным строкам, не касаясь остальных.

В Битриксе штатные таблицы уже покрыты индексами под типовые запросы ядра: по IBLOCK_ID, ACTIVE, XML_ID, привязкам к разделам и так далее. Проблемы начинаются на нетиповых выборках — по вашим свойствам, пользовательским полям, кастомным фильтрам и сортировкам, для которых готового индекса нет. Именно там и нужны свои индексы, о которых ниже.

Когда индекс помогает, а когда бесполезен

Индекс — не универсальное «сделать быстрее». Он ускоряет строго определённые операции и в некоторых случаях не даёт ничего или даже мешает. Понимание этого экономит время и бережёт базу от бесполезных индексов.

Индекс помогает, когда по колонке идёт выборочный поиск, диапазонный фильтр или сортировка, и колонка достаточно «различающая». Классика — фильтр по конкретному значению свойства, сортировка по цене или дате, поиск по артикулу. Особенно эффективен составной индекс, покрывающий сразу условие и сортировку: база и отбирает, и уже отсортированно отдаёт, без filesort.

Индекс бесполезен или почти, когда:

Поэтому индексы не «навешивают на всё подряд», а ставят прицельно — под конкретные медленные запросы, подтверждённые через EXPLAIN. Сначала находим тяжёлый запрос, смотрим план, добавляем индекс ровно под это условие, перепроверяем план. Это дисциплина, а не угадайка.

Свои индексы на пользовательские поля и свойства

Самая частая практическая задача — доиндексировать то, чего Битрикс не проиндексировал сам: значения свойств инфоблоков и пользовательские поля. Значения свойств для инфоблоков «версии 2» (рекомендованная схема хранения) лежат в таблицах вида b_iblock_element_prop_s{IBLOCK_ID} для одиночных свойств и b_iblock_element_prop_m{IBLOCK_ID} для множественных. Каждое свойство — это колонка PROPERTY_{ID}. Когда по такому свойству идёт частый фильтр или сортировка, а индекса нет, база сканирует таблицу целиком.

Лечится добавлением своего индекса. Сначала — убедиться через EXPLAIN, что запрос действительно упирается в скан этой колонки, потом создать индекс:

-- Индекс на одиночное свойство (напр. бренд) инфоблока с ID = 21
CREATE INDEX ix_prop_brand
  ON b_iblock_element_prop_s21 (PROPERTY_137);

-- Составной индекс: фильтр по свойству + сортировка по другому свойству
CREATE INDEX ix_prop_brand_price
  ON b_iblock_element_prop_s21 (PROPERTY_137, PROPERTY_145);

-- Индекс на колонку пользовательского поля (highload-блок / UF)
CREATE INDEX ix_uf_region
  ON b_hlbd_region (UF_REGION_CODE);

Несколько практических правил. Порядок колонок в составном индексе выбирают под реальный запрос: сначала колонка равенства/фильтра, потом колонка сортировки. Для highload-блоков (большие справочники характеристик, регионы, справочники совместимости) индексы на пользовательские поля так же критичны, как на обычных таблицах, — по ним идут те же фильтры. При этом штатный интерфейс highload-блоков и умного фильтра умеет создавать часть индексов сам; проверьте, что нужные уже есть, прежде чем добавлять руками.

Не забудьте про обмен. Свойства массово перезаписываются при обмене с 1С. Индекс ускоряет чтение витрины, но каждую запись в проиндексированную колонку база вынуждена ещё и обновить в индексе. Поэтому свои индексы на свойства ставят под реальные фильтры, а не «на все PROPERTY на всякий случай» — иначе обмен станет тяжелее без пользы для скорости чтения.

Как свойства и характеристики участвуют в фасетной фильтрации и почему грамотные индексы там особенно важны, мы разбираем в связке с умным фильтром и торговыми предложениями. Если проект строится вокруг больших каталогов и высоких нагрузок, схему хранения и индексы стоит проектировать сразу под highload-проект на Битриксе, где база рассчитывается с запасом по объёму и параллелизму.

Не переусердствовать: цена лишних индексов

Раз индексы так помогают чтению, почему не проиндексировать всё? Потому что у индексов есть обратная сторона, и на активно пишущем магазине она заметна. Каждый индекс нужно поддерживать в актуальном состоянии: при вставке, обновлении и удалении строки база обновляет не только саму таблицу, но и все её индексы. Чем больше индексов на таблице, тем дороже каждая запись.

Для магазина это прямо бьёт по двум сценариям. Первый — обмен с 1С, который массово пишет в таблицы свойств, товаров, остатков и цен: лишние индексы делают каждую из тысяч операций записи тяжелее. Второй — оформление заказов в пик, когда идёт активная запись в таблицы заказа и корзины. Плюс индексы занимают место на диске и в буфере InnoDB, вытесняя оттуда полезные данные.

Здоровый баланс — минимально достаточный набор индексов, каждый из которых работает на реальный запрос. Периодически стоит ревизовать индексы: какие используются, какие нет, нет ли дублей. Это часть регулярного обслуживания базы, а не разовая настройка.

InnoDB против MyISAM: почему Битрикс — InnoDB

Движок хранения определяет, как таблица работает с блокировками, транзакциями и восстановлением. Для 1С-Битрикс ответ однозначный — InnoDB, и понимать почему полезно, чтобы не оставить в базе случайных MyISAM-таблиц, которые станут узким местом.

КритерийInnoDB (нужен Битриксу)MyISAM (устаревший)
БлокировкиНа уровне строкиНа уровне всей таблицы
ТранзакцииЕсть (ACID)Нет
Запись + чтениеПараллельны, не мешаютЗапись блокирует чтение таблицы
Восстановление после сбояЖурнал, авто-восстановлениеРучная проверка, риск потери
Внешние ключиПоддерживаютсяНет

Ключевое отличие для магазина — блокировки. MyISAM блокирует таблицу целиком на время записи: пока обмен с 1С обновляет строку в таблице товаров, все посетители, которые пытаются читать эту таблицу, ждут. На активном магазине с постоянным обменом и заказами это превращается в очередь и «залипание». InnoDB блокирует только затрагиваемые строки, поэтому чтение витрины и запись обмена идут параллельно. Добавьте сюда транзакции (важны для корректности заказов и оплат) и надёжное восстановление после сбоя — и выбор очевиден.

Современные дистрибутивы «Битрикс: Управление сайтом» по умолчанию используют InnoDB. Но в старых базах, переезжавших через много версий, иногда остаются отдельные таблицы MyISAM. Их находят и переводят на InnoDB:

-- Найти таблицы, которые ещё на MyISAM
SELECT TABLE_NAME, ENGINE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
  AND ENGINE = 'MyISAM';

-- Перевести конкретную таблицу на InnoDB
ALTER TABLE b_example_table ENGINE = InnoDB;
Аккуратно с большими таблицами. ALTER TABLE ... ENGINE = InnoDB перестраивает таблицу целиком и на больших объёмах может надолго её заблокировать. На активном проде такие операции делают в окно обслуживания или через онлайн-инструменты (например, pt-online-schema-change), которые перестраивают таблицу без длительной блокировки.

Настройки MySQL/MariaDB под Битрикс

Дефолтный конфиг MySQL/MariaDB рассчитан на «работает у всех», а не на «быстро под нагрузкой». Несколько ключевых параметров определяют, будет ли база работать из оперативной памяти или упираться в диск. Ниже — карта самых важных настроек; конкретные значения подбирают под объём базы и ресурсы сервера, а не берут универсальными.

ПараметрЗа что отвечаетНа что влияет
innodb_buffer_pool_sizeПамять под данные и индексы InnoDBГлавный параметр: работа из ОЗУ вместо диска
innodb_log_file_sizeРазмер журнала транзакцийПропускная способность записи, обмен с 1С
innodb_flush_log_at_trx_commitСтратегия сброса журнала на дискБаланс скорости записи и надёжности
tmp_table_size / max_heap_table_sizeРазмер временных таблиц в памятиТяжёлые сортировки и группировки без диска
max_connectionsЛимит одновременных соединенийУстойчивость в пик, отказ «too many connections»
thread_cache_sizeПереиспользование потоков соединенийНакладные расходы на новые подключения
join_buffer_size / sort_buffer_sizeБуферы под соединения и сортировкуСкорость запросов без индекса под сортировку

Отдельно про кэш запросов (query cache): в старых версиях MySQL он существовал, но на активно пишущем магазине часто вредил (сбрасывался при каждой записи в таблицу), а в MySQL 8 его убрали совсем. MariaDB кэш запросов сохраняет, но на нагруженном магазине его обычно не включают. Полагаться на него как на «ускоритель» не стоит — реальную работу по кэшированию делает кэш Битрикса и буфер InnoDB.

[mysqld]
# --- InnoDB ---
innodb_buffer_pool_size = 4G          # под размер «горячих» данных, с запасом ОС
innodb_log_file_size    = 512M        # крупнее — легче пиковой записи (обмен)
innodb_flush_log_at_trx_commit = 2    # компромисс скорость/надёжность
innodb_file_per_table   = 1           # каждая таблица — свой файл

# --- Временные таблицы ---
tmp_table_size     = 128M
max_heap_table_size = 128M

# --- Соединения ---
max_connections    = 200
thread_cache_size  = 32

# --- Буферы на сессию (умеренно, это память НА каждое соединение) ---
join_buffer_size = 4M
sort_buffer_size = 4M
Буферы на сессию — не «чем больше, тем лучше». join_buffer_size, sort_buffer_size и подобные выделяются на каждое соединение. Задрав их до сотен мегабайт при большом max_connections, легко исчерпать всю память сервера в пик. Их держат умеренными, а память вкладывают в общий буфер InnoDB, который один на всех.

innodb_buffer_pool_size и буфер InnoDB

Если из всего конфига выбрать один самый важный параметр, это innodb_buffer_pool_size. Буфер InnoDB — это область оперативной памяти, в которой движок держит данные таблиц и индексы. Когда запрос обращается к данным, которые уже в буфере, он читает их из памяти — быстро. Когда данных в буфере нет, движок идёт за ними на диск — медленно. Цель настройки — чтобы «горячий» рабочий набор (данные и индексы, к которым сайт обращается постоянно) помещался в буфер и читался из ОЗУ.

Схема ниже показывает, как это работает вместе с кэшем приложения: запрос сначала может быть перехвачен кэшем Битрикса и вообще не дойти до базы; если дошёл — данные ищутся в буфере InnoDB, и только при промахе идёт обращение к диску.

Путь данных: кэш приложения → буфер InnoDB → диск Запрос страница магазина Кэш Битрикса HIT → ответ сразу, до базы не доходит MISS Буфер InnoDB данные и индексы в оперативной памяти MISS Диск медленно Чем больше горячих данных умещается в буфер InnoDB, тем реже запрос уходит на диск
Схема: кэш Битрикса убирает большинство обращений к базе, а буфер InnoDB держит данные и индексы в памяти, чтобы дошедшие до базы запросы не читали диск.

Как понять, что буфер мал? Косвенные признаки — база под нагрузкой активно читает с диска, растёт нагрузка на диск, а не только на процессор; статус InnoDB показывает низкую долю попаданий в буфер. Если буфер меньше рабочего набора, база постоянно «выгружает» одни данные, чтобы загрузить другие, и толком не пользуется памятью. Решение — увеличить буфер (в пределах доступной памяти, оставив запас ОС, веб-серверу и PHP) или, если памяти физически мало, переезжать на сервер помоложе. Конкретный размер зависит от объёма базы и того, что ещё живёт на сервере, поэтому его подбирают под инфраструктуру.

Связка с железом здесь прямая: сколько памяти можно отдать под буфер, определяет хостинг. Как выбрать конфигурацию сервера и распределить ресурсы между базой, PHP и кэшем, мы разбираем в материале про хостинг и инфраструктуру для Битрикса и BitrixVM.

Временные таблицы, сортировки и соединения

Кроме буфера InnoDB, на скорость влияют настройки, связанные с обработкой самих запросов. Когда запрос сортирует или группирует большой объём данных, база создаёт временную таблицу. Если она помещается в память (tmp_table_size / max_heap_table_size), операция быстрая; если превышает лимит — временная таблица «падает» на диск, и запрос резко замедляется. В EXPLAIN это видно как Using temporary, а на диске — как временные файлы под тяжёлые группировки.

Лечится это двумя путями. Идеально — убрать саму необходимость временной таблицы и сортировки: подходящий индекс отдаёт данные уже отсортированными, без filesort и temporary. Когда это невозможно (сложная аналитика, отчёты), помогает поднятие лимитов временных таблиц в памяти — но умеренно, помня, что часть буферов выделяется на каждое соединение.

Отдельная тема — соединения. Параметр max_connections задаёт, сколько клиентов могут одновременно работать с базой. В пик (распродажа, наплыв трафика, параллельный обмен) лимит может исчерпаться, и появляется ошибка «too many connections» — новые запросы просто не обслуживаются. Но и задирать лимит бесконтрольно нельзя: каждое соединение потребляет память, и слишком большой лимит при больших сессионных буферах способен исчерпать ОЗУ. Здоровый путь — разумный лимит соединений плюс кэш Битрикса, который уменьшает само число обращений к базе, и вынесение сессий из базы в память.

Сессии — скрытая нагрузка на базу. По умолчанию сессии могут храниться в базе, и на сайте с большим онлайном таблица сессий становится точкой конкуренции за запись. Вынесение сессий в память (Redis/memcached) снимает эту нагрузку с базы. Это не про кэш данных, а именно про разгрузку БД от служебной записи.

Большие таблицы Битрикса и их обслуживание

В магазине на Битриксе есть таблицы, которые растут особенно быстро и первыми становятся тяжёлыми. Их полезно знать «в лицо» — чтобы понимать, где искать распухание и что обслуживать в первую очередь.

ТаблицаЧто хранитПочему растёт / что делать
b_iblock_element_prop_s* / _m*Значения свойств элементовСтрока на каждое значение каждого товара — индексы, кэш, обслуживание
b_iblock_elementЭлементы инфоблоков (товары)Большой каталог — следить за индексами под фильтры
b_sale_order, b_sale_basketЗаказы и корзиныКопятся годами — архивация старых, чистка брошенных корзин
b_sale_order_historyИстория изменений заказовРастёт быстрее самих заказов — архивировать/чистить
b_search_content*Поисковый индексДублирует контент — переиндексация, контроль объёма
b_stat_*Данные модуля статистикиОгромный объём хитов — чистка старых периодов
b_event_logЖурнал событийЛоги безопасности и ошибок — ограничить срок хранения
b_perf_*Данные монитора производительностиЧистить после диагностики, не держать сбор постоянно

Большой размер таблицы сам по себе — не диагноз. Таблица свойств обязана быть большой на большом каталоге, это нормально. Обслуживание нужно, когда по таблице идут медленные запросы или когда таблица разрослась «мусором» (устаревшие логи, статистика за годы, брошенные корзины анонимов). Базовое обслуживание InnoDB-таблиц:

-- Обновить статистику оптимизатора (быстро, помогает выбирать индексы)
ANALYZE TABLE b_iblock_element_prop_s21;

-- Дефрагментация и пересборка таблицы (тяжелее, делать в окно обслуживания)
OPTIMIZE TABLE b_sale_order_history;

-- Посмотреть размеры таблиц базы (data + index), топ по объёму
SELECT TABLE_NAME,
       ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024) AS size_mb
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC
LIMIT 20;

ANALYZE TABLE обновляет статистику, по которой оптимизатор выбирает индексы, — это дёшево и полезно делать регулярно. OPTIMIZE TABLE для InnoDB фактически пересобирает таблицу, устраняя фрагментацию после массовых удалений; операция тяжёлая и блокирующая, её планируют на окно обслуживания или проводят онлайн-инструментами. Запрос к information_schema даёт список самых больших таблиц — с него удобно начинать ревизию распухания.

Чистка и архивация: журнал, статистика, индекс

Значительная часть «распухания» базы — это не боевые данные, а служебное и устаревшее: логи, статистика хитов, старые сессии, дубли поискового индекса, брошенные корзины анонимов. Их можно и нужно чистить и архивировать, не трогая заказы и товары. Схема ниже показывает идею: распухшую таблицу разделяют на «живое» (оставить) и «устаревшее» (в архив или удалить), после чего обслуживают.

Распухшая таблица → чистка и архивация Было: всё в одной актуальные данные актуальные данные актуальные данные устаревшие данные устаревшие данные устаревшие данные оставить вынести Рабочая таблица компактная, быстрая только актуальное Архив / удаление логи, статистика, старые периоды OPTIMIZE дефрагментация после чистки
Схема: устаревшие данные (логи, статистика, старые периоды) выносят в архив или удаляют, оставляя рабочую таблицу компактной, после чего дефрагментируют её.

Что и как чистят в магазине на Битриксе, штатными средствами и по расписанию:

  1. Журнал событий. В настройках главного модуля задают срок хранения журнала событий (b_event_log). Без ограничения он растёт бесконечно. Ставят разумный срок — и старые записи чистятся автоматически.
  2. Статистика. Модуль статистики копит хиты и сессии в таблицах b_stat_* — это одни из самых объёмных данных. Если детальная статистика не нужна, её ограничивают по сроку хранения или отключают сбор, оставив внешнюю аналитику.
  3. Поисковый индекс. Таблицы поиска дублируют контент и разрастаются. Их периодически переиндексируют начисто и контролируют объём; если внутренний поиск не используется, индексацию отключают.
  4. Брошенные корзины и сессии. Корзины анонимных пользователей (b_sale_basket с истёкшим fuser) и старые сессии копятся. Их чистят штатными агентами по сроку.
  5. История заказов и старые заказы. b_sale_order_history растёт быстрее заказов. Очень старые заказы и историю архивируют по бизнес-правилам (с учётом требований к хранению).
  6. Данные монитора. После диагностики сбор монитора производительности выключают и чистят его таблицы — держать его включённым постоянно незачем.
Сначала бэкап, потом чистка. Любая массовая чистка и архивация делается после свежей резервной копии и, по возможности, сначала на копии базы. Заказы и первичные данные не удаляют «для скорости» — их архивируют по правилам хранения. Скорость важна, но не ценой утраты данных.

Партиционирование больших таблиц (обзорно)

Партиционирование — способ разбить одну большую таблицу на несколько физических секций по какому-то ключу, оставаясь для приложения одной таблицей. Например, историю заказов или логи можно партиционировать по годам. Идея в том, что запрос, который бьёт по одному году, читает только соответствующую секцию, а не всю таблицу, а старые секции можно целиком отцепить и заархивировать одной быстрой операцией вместо массового DELETE.

Звучит привлекательно, но для типичного магазина партиционирование — не первый и обычно не нужный инструмент. Причин несколько. Во-первых, выигрыш появляется, только когда запросы почти всегда попадают в одну секцию (по ключу партиционирования); если фильтры идут по другим полям, база всё равно обходит все секции. Во-вторых, штатные таблицы Битрикса не рассчитаны на ручное партиционирование, и вмешательство в их структуру усложняет обновления и поддержку. В-третьих, грамотные индексы, кэш и настройка буфера дают несравнимо больший эффект при меньшем риске.

Партиционирование оправдано в highload-сценариях с действительно огромными и быстро растущими таблицами — история заказов за много лет, логи, аналитика, — где данные естественно делятся по времени и старые периоды регулярно архивируют. Подходить к нему стоит осознанно и только после того, как исчерпаны индексы, кэш и настройки сервера. Это инструмент «когда база большая и растёт по времени», а не «когда хочется, чтобы было быстрее».

Репликация и разделение чтения/записи

Когда одному серверу базы перестаёт хватать мощности даже после оптимизации, следующий архитектурный шаг — репликация: копия базы на отдельном сервере, которая автоматически повторяет за основным все изменения. Основной сервер (мастер) принимает запись, реплики (слейвы) держат актуальную копию и обслуживают чтение. Поскольку в магазине чтений на порядок больше, чем записи, чтение распределяют по репликам, разгружая мастер.

Разделение чтения и записи через репликацию Битрикс модуль веб-кластера запись (INSERT/UPDATE) чтение (SELECT) Мастер принимает запись, источник истины Реплика 1 только чтение Реплика 2 чтение репликация данных
Схема: запись идёт на мастер, он реплицирует изменения на реплики, а чтение витрины распределяется по репликам — так снимается нагрузка с основного сервера базы.

Хорошая новость: в 1С-Битрикс есть штатный модуль веб-кластера, который умеет работать с репликацией из коробки. Он знает про несколько подключений к базе и сам направляет запись на мастер, а чтение — на реплики, не требуя переписывать код компонентов. Подключения настраиваются в конфигурации (.settings.php), а модуль распределяет запросы по ролям серверов.

Важная тонкость — задержка репликации. Реплика получает изменения с небольшим отставанием от мастера, поэтому данные, только что записанные, могут ещё не появиться на реплике. Для критичных сценариев (сразу после оформления заказа показать этот заказ) чтение направляют на мастер, а на реплики отдают то, где секундная задержка некритична (каталог, витрина). Модуль кластера это учитывает. Репликация и разделение ролей — инструмент highload: для среднего магазина сначала выжимают всё из индексов, кэша и настроек одного сервера, и только при реальном упоре в мощность переходят к кластеру. Такие архитектуры мы проектируем в рамках highload-проектов на Битриксе.

Кэш БД и кэш Битрикса: в чём разница

Слово «кэш» звучит и про базу, и про Битрикс, и их регулярно путают, теряя эффект. На самом деле это разные уровни, которые дополняют друг друга.

УровеньЧто кэшируетЧто даёт
Буфер InnoDBДанные и индексы таблиц в памятиБыстрое выполнение самого SQL-запроса
Кэш запросов MySQL (устар.)Результаты одинаковых SELECTМало пользы на пишущем магазине, в MySQL 8 убран
Кэш компонентов БитриксаРезультат блока (список, меню)Запрос вообще не доходит до базы
Теговый кэш БитриксаКэш с инвалидацией по событиюСвежесть данных без лишней пересборки
Композит / HTML-кэшСобранную страницу целикомОтдача статики до запуска ядра и базы

Ключевая мысль: кэш на стороне базы ускоряет выполнение запроса, но запрос всё равно доходит до базы, разбирается и выполняется. Кэш Битрикса работает выше и вообще не даёт запросу дойти до базы — готовый результат берётся из кэша приложения. Поэтому правильная стратегия двухуровневая: кэш Битрикса убирает большинство обращений к базе, а настройки MySQL/MariaDB ускоряют те запросы, которые всё же доходят (первая «холодная» сборка, персональные некэшируемые данные, обмен с 1С). Одно без другого работает вполсилы: идеальный конфиг базы не спасёт сайт с выключенным кэшем компонентов, а отличный кэш не поможет тяжёлому обмену, который пишет напрямую в базу.

Подробный разбор уровней кэша приложения — теговый кэш, автокомпозит, memcached и Redis, прогрев и инвалидация — в отдельном материале про кэширование в 1С-Битрикс. Здесь важно запомнить одно: база и кэш — не конкуренты, а два этажа одной системы, и оптимизируют их вместе.

Обмен с 1С и нагрузка на базу

Обмен с учётной системой — главный источник тяжёлой записи в базе магазина, и именно вокруг него возникает больше всего проблем производительности БД. Обмен массово пишет и обновляет товары, свойства, цены, остатки — тысячи операций записи, каждая из которых ещё и обновляет индексы затронутых таблиц. Если обмен идёт в час пик, он конкурирует с чтением витрины за ресурсы базы: посетители ждут, пока обмен занимает диск и процессор.

Несколько принципов, которые снимают эту боль:

Связка «база + обмен + кэш» — единая цепочка: обмен пишет в базу, база обслуживает запись быстрее при правильных настройках и разумных индексах, а кэш после обмена инвалидируется и прогревается, чтобы чтение шло не из базы. Механику самого обмена, форматы и расписание мы разбираем в материалах рубрики про интеграции; здесь важно, что обмен нужно рассматривать как нагрузку на БД и планировать соответственно.

Мониторинг базы данных

Оптимизация — не разовая акция, а процесс: каталог растёт, добавляются фильтры, копятся заказы и логи, и то, что работало полгода назад, снова становится узким местом. Чтобы ловить деградацию до того, как её заметят посетители, нужен постоянный мониторинг базы. Смотрят на несколько групп показателей.

Что мониторитьО чём говорит
Доля попаданий в буфер InnoDBХватает ли памяти под горячие данные
Число и время медленных запросовНе появились ли новые тяжёлые запросы
Число активных соединенийБлизость к лимиту в пик
Временные таблицы на дискеТяжёлые сортировки/группировки без индексов
Задержка репликации (если есть)Насколько реплики отстают от мастера
Рост размеров ключевых таблицКогда пора чистить и обслуживать

Инструменты бывают разные: встроенный монитор производительности Битрикса и его панель, статус-переменные MySQL (SHOW GLOBAL STATUS, SHOW ENGINE INNODB STATUS), внешние системы мониторинга с дашбордами и алертами по метрикам базы. Практичный минимум — регулярно смотреть slow query log и размеры таблиц, а на нагруженных проектах поставить внешний мониторинг с оповещениями. Как выстроить логирование и наблюдаемость на проекте в целом, включая базу, разбирается в материалах по инфраструктуре и мониторингу; здесь важно завести привычку: измерять не только когда «уже тормозит», а постоянно.

Частые ошибки оптимизации БД

Проблемы с базой в магазинах на Битриксе повторяются. Зная их заранее, вы сэкономите недели отладки.

Чек-лист оптимизации БД

Короткий список, по которому удобно свериться при работе с базой магазина:

Вывод

Оптимизация базы данных для 1С-Битрикс — это не одна волшебная настройка, а дисциплина «измерил → нашёл узкое место → устранил → перепроверил». Сначала находят конкретные медленные запросы через slow query log, монитор производительности и EXPLAIN. Потом лечат их точечно: чаще всего не хватает индекса — иногда своего, на свойство инфоблока или пользовательское поле, — а иногда узкое место в памяти, и помогает буфер InnoDB под размер горячих данных. Всё это на движке InnoDB, который единственно правильный для магазина с его постоянной записью и обменом.

Дальше — гигиена больших таблиц: знать самые тяжёлые (свойства, заказы, история, логи, статистика, поиск), обслуживать их, чистить служебное и архивировать устаревшее, не трогая боевые данные. И только когда одному серверу базы после всей оптимизации перестаёт хватать мощности, в игру входят highload-инструменты — партиционирование и репликация с разделением чтения и записи через модуль веб-кластера. Важнее всего помнить: база и кэш Битрикса — два этажа одной системы, и работают они в связке. Наведите порядок в обоих по этому чек-листу — и магазин будет держать нагрузку, а не падать в час пик и после обмена. Другие материалы по производительности и архитектуре собраны в рубрике «Разработка и архитектура».

Частые вопросы

С чего начать оптимизацию базы данных в 1С-Битрикс?

Не с правки конфига «наугад», а с измерения. Сначала нужно понять, какие запросы реально тормозят: включить slow query log MySQL/MariaDB, посмотреть «Монитор производительности» самого Битрикса и отладочную панель, где видно число и время SQL-запросов на страницу. Когда список тяжёлых запросов на руках, каждый разбирают через EXPLAIN и решают точечно: не хватает индекса — добавить индекс, запрос собирает слишком много данных — поправить выборку или включить кэш, узкое место в памяти — увеличить буфер InnoDB. Такой порядок «измерил → нашёл узкое место → устранил → перепроверил» экономит недели по сравнению с тюнингом вслепую.

Как найти медленные запросы к базе?

Есть три взаимодополняющих источника. Первый — slow query log MySQL/MariaDB: в конфиг добавляют slow_query_log и long_query_time, и сервер сам пишет в файл все запросы дольше порога; собрать статистику по логу удобно утилитой вроде mysqldumpslow или pt-query-digest. Второй — модуль «Монитор производительности» в Битриксе: он ведёт свою таблицу тяжёлых запросов, привязанных к страницам сайта, и показывает их прямо в админке. Третий — встроенная отладка Битрикса и отладочная панель: на конкретной странице видно, сколько запросов выполнилось и сколько времени заняла база. Первые два дают картину «в целом по сайту», третий — точечную диагностику одной страницы.

Нужно ли добавлять свои индексы на свойства инфоблоков?

Часто да — но по факту, а не заранее. Значения свойств хранятся в больших таблицах (для инфоблоков «версии 2» это b_iblock_element_prop_sIBLOCK и b_iblock_element_prop_mIBLOCK), и когда по свойству идёт фильтрация или сортировка, без индекса база сканирует эти таблицы целиком. Если EXPLAIN показывает на таком запросе full scan и запрос попадает в медленные, свой индекс на колонку свойства (или составной индекс по паре колонок) снимает проблему. Но добавлять индексы «на всякий случай» на все свойства не нужно: каждый индекс замедляет вставку и обновление и раздувает таблицу, а обмен с 1С как раз массово пишет в эти таблицы. Индексируют то, по чему реально фильтруют и сортируют.

Какой размер innodb_buffer_pool_size выставить?

Общий ориентир: буфер InnoDB — самый важный параметр памяти, в него должны помещаться «горячие» данные и индексы, к которым обращается сайт. На выделенном сервере под базу его обычно поднимают до значительной доли доступной оперативной памяти, оставляя запас операционной системе и остальным процессам (веб-серверу, PHP, кэшу). На виртуальном хостинге, где память общая, ориентируются на реальный объём базы и лимиты тарифа. Точное «правильное» число зависит от размера базы и того, сколько ещё сервисов живёт на этом же сервере, поэтому его подбирают под конкретную инфраструктуру, а не берут из универсальной таблицы. Признак, что буфер мал, — база постоянно читает данные с диска вместо памяти под нагрузкой.

InnoDB или MyISAM для магазина на Битриксе?

Для 1С-Битрикс — InnoDB, это официально рекомендованный и де-факто стандартный движок. InnoDB даёт транзакции и блокировки на уровне строк: когда обмен с 1С пишет в таблицу, параллельные посетители продолжают читать её без блокировки всей таблицы. MyISAM блокирует таблицу целиком на запись, поэтому на активном магазине с постоянным обменом он становится узким местом и вдобавок хуже переживает аварийные остановки. Современные сборки БУС уже используют InnoDB; если в старой базе остались таблицы MyISAM, их обычно переводят на InnoDB. Исключение — некоторые служебные таблицы полнотекстового поиска, но это частные случаи, а не повод держать каталог и заказы на MyISAM.

Почему таблица свойств элементов такая большая и что с ней делать?

Таблицы значений свойств (b_iblock_element_prop_sIBLOCK для одиночных и b_iblock_element_prop_mIBLOCK для множественных) хранят по строке на каждое значение каждого свойства каждого товара. На каталоге с десятками тысяч позиций и множеством характеристик это легко превращается в одну из самых больших таблиц базы. Сама по себе величина — не болезнь; лечить её нужно, только если по этим таблицам идут медленные запросы. Тогда помогают: правильные индексы под конкретные фильтры и сортировки, включённый и работающий кэш инфоблоков (чтобы повторные выборки шли из кэша, а не из базы), корректная выборка свойств разом вместо запроса в цикле (борьба с эффектом N+1) и периодическое обслуживание таблицы (ANALYZE/OPTIMIZE). Массово удалять данные оттуда нельзя — это фактические значения товаров.

Помогает ли партиционирование обычному интернет-магазину?

Обычному среднему магазину — почти никогда, и внедрять его «для скорости» не нужно. Партиционирование делит одну большую таблицу на секции по какому-то признаку (например, заказы по годам) и выигрывает в узких сценариях: когда запросы почти всегда бьют по одной секции или когда старые секции целиком архивируют и отцепляют. Для типичного каталога грамотные индексы, кэш и настройка буфера дают несравнимо больший эффект при меньшем риске. Партиционирование — инструмент highload-проектов с действительно огромными таблицами (история заказов, логи, статистика за годы), и подходить к нему стоит осознанно, после того как исчерпаны индексы, кэш и настройки сервера.

Чем кэш MySQL отличается от кэша Битрикса?

Это разные уровни, и они не заменяют друг друга. Кэш на стороне базы (буфер InnoDB, кэши движка) ускоряет выполнение самих SQL-запросов: данные и индексы держатся в памяти, поэтому запрос отрабатывает быстрее. Но запрос всё равно доходит до базы, разбирается и выполняется. Кэш Битрикса (кэш компонентов, теговый кэш, композит) работает выше: он вообще не даёт запросу дойти до базы — готовый результат берётся из кэша приложения. Поэтому правильная стратегия двухуровневая: кэш Битрикса убирает большинство обращений к базе, а настройки MySQL/MariaDB ускоряют те запросы, которые всё же доходят до неё (первая сборка, некэшируемые персональные данные, обмен с 1С).

Поделиться:

Магазин упирается в базу под нагрузкой?

Найдём медленные запросы, добавим нужные индексы, настроим MySQL/MariaDB и буфер InnoDB, обслужим большие таблицы и разгрузим базу от обмена с 1С. Рассчитаем работу по вашему магазину.

Услуга «Ускорение сайта»

Игорь Воскресенский

Команда студии B2Bsite. С 2014 года разрабатываем, ускоряем и поддерживаем интернет-магазины на 1С-Битрикс: оптимизация базы данных и запросов, индексы и настройка MySQL/MariaDB, кэширование и композит, обмен с 1С и highload-архитектуры для среднего и крупного бизнеса.

← Все статьи блога