innodb_buffer_pool_size задаёт, сколько памяти InnoDB отводит под кэш страниц данных и индексов — это самый влиятельный параметр MySQL для производительности на VPS, и при этом один из самых часто занижаемых или, наоборот, выставленных на всю доступную RAM без остатка.
Что именно кэширует buffer pool
Buffer pool хранит в памяти страницы таблиц и индексов InnoDB, которые читались или изменялись, избегая повторного чтения с диска при повторном обращении к тем же данным. Это касается только таблиц InnoDB: для MyISAM память кэшируется отдельным параметром key_buffer_size, а разница движков разобрана в статье про InnoDB и MyISAM.
Если весь рабочий набор данных помещается в buffer pool целиком, диск почти не используется для чтения — читает его только запись изменений и редкие операции вроде полного сканирования таблицы. Если набор данных больше buffer pool, часть страниц вытесняется и перечитывается заново, и чем больше это несовпадение, тем выше нагрузка на диск.
Почему нельзя просто отдать под буфер всю RAM
Кроме InnoDB, на сервере работает операционная система, сама MySQL резервирует память на каждое соединение под сортировку и join (sort_buffer_size, join_buffer_size), а если MySQL делит VPS с PHP-FPM, Nginx или Redis, этим сервисам тоже нужна память. Значение в 100% RAM гарантированно приводит к своппингу при первом же всплеске соединений.
Практический ориентир для сервера, где MySQL — главная нагрузка: 50-70% от общей RAM. Если на том же VPS крутится PHP-FPM и сайт, долю стоит снижать до 30-40%, оставляя остальное под процессы PHP, бюджет которых разобран в статье про расчёт pm.max_children.
Формула и пример расчёта
Формула в общем виде: buffer_pool = общая RAM минус память под ОС и другие сервисы минус запас на соединения, умноженное на выбранную долю. На VPS с 4 GB RAM, где MySQL делит сервер с PHP-FPM и Nginx, после вычета 1 GB под систему и сервисы остаётся около 3 GB, из которых под буфер стоит взять 50-60%, то есть 1.5-1.8 GB как стартовую точку.
- Размер всего рабочего набора данных — если база меньше буфера, увеличивать его дальше бессмысленно
- Число одновременных соединений и их sort_buffer_size, join_buffer_size
- Другие сервисы на том же VPS — PHP-FPM, Redis, Nginx
- Настройка swappiness в ядре — низкое значение снижает риск вытеснения буфера в swap
- Время прогрева после перезапуска — пустой буфер читает с диска, пока не наполнится заново
Таблица: стартовые значения по объёму RAM
Диапазоны в таблице — точка старта для дальнейшего замера на своей нагрузке, а не готовый ответ для любого сервера.
| RAM сервера | MySQL — главный сервис | MySQL делит VPS с PHP/Nginx |
|---|---|---|
| 2 GB | 1-1.2 GB | 0.5-0.7 GB |
| 4 GB | 2.5-3 GB | 1.5-1.8 GB |
| 8 GB | 5-6 GB | 3-4 GB |
| 16 GB | 10-12 GB | 6-8 GB |
Как проверить, что размер подобран верно
Точный ответ дают статусные переменные, а не таблица выше: соотношение Innodb_buffer_pool_reads (страниц, прочитанных с диска) к Innodb_buffer_pool_read_requests (всех обращений к страницам, включая кэш) показывает долю промахов кэша. Если после суток работы под обычной нагрузкой доля промахов заметна и продолжает расти, буфер стоит увеличить; если она почти не меняется при увеличении буфера, рабочий набор уже кэшируется целиком.
Отдельная и частая путаница — рост файла ibdata1 на диске: он не связан напрямую с innodb_buffer_pool_size и не уменьшается при его изменении, разбор того, откуда берётся этот рост, в статье про ibdata1 и место на диске.
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
SET GLOBAL innodb_buffer_pool_size = 1610612736;Частые вопросы
Можно ли менять innodb_buffer_pool_size без перезапуска MySQL?
В современных версиях MySQL размер можно менять динамически через SET GLOBAL, но изменение применяется постепенно и само значение не сохраняется после перезапуска без правки my.cnf.
Большой буфер решит проблему медленных запросов?
Нет: буфер ускоряет чтение уже прочитанных страниц, но запрос без нужного индекса всё равно читает лишние страницы при каждом выполнении; работа с индексами разобрана в статье про индексы MySQL.
После перезапуска сервер стал медленнее, хотя buffer_pool_size не менялся?
Это ожидаемо: сразу после старта буфер пуст, и первые запросы читают страницы с диска, пока кэш не прогреется заново; скорость возвращается по мере накопления в буфере рабочего набора данных.