Влияние размера индекса MySQL на скорость запросов
Уникальный индекс MySQL хранится в отдельном B‑Tree. Размер id2 влияет только на кэш буфера; запросы по id1 не замедляются, пока его страницы в памяти. При конкуренции за буфер‑пул возможны косвенные задержки.
Влияет ли размер индекса на скорость запросов в MySQL? У меня два уникальных индекса: id1 (integer) и id2 (char(255)). При миллиардах записей индекс по id2 может не помещаться в RAM, что замедлит запросы по нему. Но как это скажется на запросах только по id1? Оба индекса хранятся отдельно, но стоит ли опасаться влияния одного индекса на другой, особенно при больших объёмах данных и возможных ALTER TABLE?
Уникальный индекс хранится в отдельном B‑Tree‑проекте, поэтому его размер влияет только на то, какие страницы этого индекса будут помещены в буфер‑пул. Если id2 превышает доступную память, запросы по id2 будут загружать страницы с диска, а запросы по id1 принципиально не замедляются, пока в буфере остаются страницы его индекса. Тем не менее, при большом объёме данных и малом буфере могут наблюдаться конкуренции за кэш, что косвенно может немного замедлить любые операции.
Содержание
- Как индексы хранятся в InnoDB
- Влияние размера индекса на кэш и I/O
- Параллельные запросы и конкуренция за буфер‑пул
- ALTER TABLE и перестройка индексов
- Оптимизация размеров индексов
Как индексы хранятся в InnoDB
InnoDB хранит каждый индекс в собственном B‑Tree‑файле, разделённом на 16 КБ‑страницы.
Локальный ключ — это первичный ключ, а все вторичные индексы включают копию первичного ключа. Поэтому размер вторичного индекса = размер колонок индекса + размер PK.
“Secondary indexes contain a copy of the primary key columns” — MySQL Reference Manual.
Влияние размера индекса на кэш и I/O
-
Буфер‑пул кэширует как данные, так и индексы. Если индекс занимает больше, чем доступно в памяти, его страницы будут вытесняться, а запросы к нему станут обращаться к диску.
“If the index grows much larger than RAM, there’s not enough buffer pool to hold the whole index” — DBA Stack Exchange.
-
Показатели производительности: чтение по индексу с большим размером идёт за счёт последовательного чтения страниц. Если страницы не в кэше, каждая страница требует I/O, что увеличивает время ответа.
“Performance of index scans follows size directly” — Stack Overflow.
-
Влияние на другие индексы: в общем случае индексы независимы, но все они используют один и тот же буфер‑пул. При нехватке памяти страницы больших индексов вытесняют страницы малых, что может косвенно влиять на скорость запросов к небольшим индексам.
Параллельные запросы и конкуренция за буфер‑пул
- Если запросы по id1 и id2 вызываются одновременно, InnoDB сначала загружает нужные страницы обоих индексов. Если буфер‑пул заполнен, LRU‑политика вытесняет «меньшие» страницы.
- В реальных нагрузках, если id1 — целое число (4 Б) и индекс небольшой, вероятность, что его страницы будут вытеснены, низка, если одновременно идёт интенсивная работа с id2.
- При больших объёмах данных, когда обе таблицы «плотно» используют один буфер‑пул, стоит рассмотреть увеличение
innodb_buffer_pool_sizeили разделение таблиц/индексов по разным таблицам/схемам.
ALTER TABLE и перестройка индексов
- Любой
ALTER TABLE(добавление, удаление, изменение индекса) приводит к перестройке таблицы и всех её индексов. - При перестройке создаётся новая копия таблицы, а старые страницы освобождаются. Если таблица содержит миллиарды строк, это может занять часы и потребовать большого объёма временного пространства.
- При больших индексах время перестройки растёт пропорционально их размеру, но это не влияет на работу других индексов в момент перестройки, потому что все они перестраиваются одновременно.
“There is no direct impact of adding new index on MySQL memory usage” — Stack Overflow.
Оптимизация размеров индексов
- Используйте подходящий тип:
char(255)хранит 255 Б даже если строка короче. Замените наvarchar(255)илиvarchar(64)/binary(16)для UUID. - Сократите длину: если логика позволяет, храните только первые N символов, если они уникальны.
- Проверяйте дублирование: иногда создаются лишние индексы, которые не нужны.
- Мониторьте буфер‑пул:
SHOW STATUS LIKE 'innodb_buffer_pool_%'иSHOW VARIABLES LIKE 'innodb_buffer_pool_size'. - Параметры кэша:
innodb_buffer_pool_instancesпомогает распределить нагрузку при больших пуле.
Заключение
- Влияние размера индекса: индексы хранятся отдельно, поэтому размер id2 не напрямую замедляет запросы по id1.
- Кэш и I/O: при нехватке памяти страницы id2 будут читать с диска, но это не затронет id1, пока его страницы находятся в кэше.
- Конкуренция за буфер‑пул: при интенсивной работе с обоими индексами и ограниченном буфере возможна косвенная деградация, но её можно смягчить увеличением
innodb_buffer_pool_size. - ALTER TABLE: перестройка таблицы приводит к пересозданию всех индексов, но не влияет на работу других индексов в момент перестройки.
- Оптимизация: используйте более компактные типы данных, убирайте дубли, следите за размером буфера.
Источники
- MySQL Reference Manual – Index Structure
- DBA Stack Exchange – Performance degrade as indices become larger
- Stack Overflow – Performance gain by reducing index size
- Percona Blog – Table size after adding a simple index
- Stack Overflow – Performance impact to adding MySQL index to large table
- DBA Stack Exchange – Indexing and performance when index size > data size