key_buffer_size应根据MyISAM索引实际大小(information_schema.TABLES中index_length总和)设为80%~90%,并结合Key_reads/Key_read_requests命中率(目标>99.9%)动态调整,超4GB需注意64位系统限制及OS内存预留。

key_buffer_size 设多大才不浪费又够用
别直接填“总内存的25%”——这个值只在 MyISAM 是主力引擎、且索引总量明确时才有点参考价值。真正靠谱的做法是先看当前索引缓存压力:SHOW STATUS LIKE 'Key_read%';,算出命中率:1 - (Key_reads / Key_read_requests)。低于 0.999 就说明经常掉磁盘,得加;高于 0.9995 且 key_blocks_unused 占比长期超 30%,说明设大了,内存白占。
再查索引实际大小:用 SELECT SUM(index_length) FROM information_schema.tables WHERE engine='MyISAM';,结果单位是字节。把这个值乘以 1.2,就是较安全的 key_buffer_size 下限。比如索引共 4.2G,那就至少设成 5G。
注意几个硬限制:
-
key_buffer_size在 64 位 Linux 上最大支持4G(MySQL 5.0.52+ 允许更大,但内核或 malloc 实际可能截断) - 超过物理内存 40% 容易触发系统 swap,响应延迟陡增
- 必须留至少
2G给 OS 缓存 .MYD 数据文件,MyISAM 不缓存数据,全靠 OS 层
为什么改完配置重启后读取还是慢
因为 key_buffer_size 是全局静态参数,改完不重启等于没改。但更常见的问题是:你只调了它,其他环节还在拖后腿。
MyISAM 一次查询要过好几道缓冲区,缺一不可:
-
read_buffer_size太小(默认128K)→ 全表扫描卡在读数据块,建议设为512K~2M,但别超4M,否则高并发下线程一多就 OOM -
table_open_cache不够 → 每次访问不同 MyISAM 表都要重新打开 .MYI 文件,开销极大;若常访问 >200 张表,至少设到2000 -
query_cache_type = 0必须关掉 → MyISAM 表只要有一行写入,整个表的查询缓存全失效,读写混合场景下反而严重拉低吞吐
这些参数都在 [mysqld] 段里配,改完一起重启。
能不能给不同 MyISAM 表分配独立 key buffer
能,但只在 MySQL ≥5.1 且真有热冷分离需求时才值得搞。比如一张高频查询的用户索引表 + 十几张低频日志表,可以避免冷表把热索引挤出缓存。
操作分三步:
- 在配置文件里定义新缓存:
hot_cache.key_buffer_size = 1G - 启动后执行:
CACHE INDEX user_index_table IN hot_cache; - 后续对该表的索引操作就走
hot_cache,不再争抢默认缓存
注意:key_buffer_size 是全局变量,hot_cache.key_buffer_size 这种写法只能在运行时用 SET GLOBAL 设置,不能写死在配置文件里;而且一旦设为 0,MySQL 会自动把该缓存里的索引块迁回默认缓存并清空命名空间。
验证是否真的生效了
重启后别只看 SHOW VARIABLES,重点盯三个状态值:
-
Key_reads是否明显下降(对比重启前 5 分钟均值) -
Key_read_requests不变或微升,但Key_reads掉一半以上,才算有效 -
key_blocks_used / (key_blocks_used + key_blocks_unused)稳定在70%~85%区间,说明既没浪费也没挤兑
最容易被忽略的是:MyISAM 的索引缓存只对 .MYI 生效,.MYD 仍走 OS page cache。所以即使 key_buffer_size 调得再准,如果系统 free -h 显示可用内存长期低于 1G,.MYD 读取照样频繁换页——这时候得调操作系统,不是调 MySQL。



















