key_buffer_size设太大直接触发系统换页,因mysql仅向os申请内存,超可用物理内存减预留后会引发swap,导致查询延迟陡增;该参数仅对myisam有效,innodb环境下纯属浪费且挤占其他内存资源。

key_buffer_size设太大直接触发系统换页
MySQL本身不管理物理内存分配,key_buffer_size只是向操作系统“申请”一块连续内存区域。一旦这个值超过可用物理内存减去系统预留(如内核、其他进程、文件系统缓存)后的余量,Linux 就会开始 swap —— 把部分内存页写入磁盘交换区。此时哪怕 SHOW STATUS LIKE 'Key%' 看起来命中率很高,实际查询延迟会陡增,因为索引块读取要等磁盘 I/O。
- 典型现象:MySQL 响应变慢、
vmstat显示si/so列持续非零、dmesg可能报Out of memory: Kill process mysqld - MyISAM 表本身不缓存数据,只缓存索引;但 OS 层面仍需为数据页留出足够 page cache,否则
read()系统调用也会卡住 - 64 位系统虽支持 >4GB 的
key_buffer_size,但若单进程 RSS 超过 90% 物理内存,风险极高
只对 MyISAM 有效,InnoDB 场景下纯属浪费
如果你的库已全量迁移到 InnoDB(2026 年绝大多数生产环境都是),调大 key_buffer_size 不仅无效,还会挤占本该留给 innodb_buffer_pool_size 或 OS 缓存的内存。InnoDB 的数据+索引都走自己的缓冲池,key_buffer_size 对它完全透明。
- 检查是否真用 MyISAM:
SELECT ENGINE, COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys') GROUP BY ENGINE;—— 若结果里没有MyISAM,就别碰这个参数 - 即使有少量 MyISAM 表(比如日志表、统计中间表),其索引总大小通常也就几十 MB,配个
64M或128M已足够 -
SHOW GLOBAL STATUS LIKE 'Key%'中Key_reads持续为 0,说明当前key_buffer_size已满足需求,再加无意义
配置错误导致值被静默忽略
key_buffer_size 是个脆弱的配置项:写错位置、单位格式不对、拼写偏差,MySQL 启动时不会报错,而是默默沿用默认值(通常是 8M 或 16M)。你以为设了 2G,实际还是 8M,问题没解决,还误判了内存压力来源。
- 必须放在
[mysqld]段下,不能在[client]或[mysql]下 - 单位必须大写且紧贴数字:
key_buffer_size = 256M✅,256m❌,256 MB❌,268435456(字节数)虽可但易读性差 - 名字不能少下划线:
key_buffer或key-buffer-size都无效,只能是key_buffer_size - 修改后必须重启 MySQL 生效,
SET GLOBAL动态设置仅对当前会话的 key cache 名称有效,不能改默认 buffer 大小
多 key_buffer 场景下容易误配
MySQL 支持创建多个命名 key buffer(如 hot_cache.key_buffer_size),但默认 buffer(即未指定名称的)始终存在且不可删除。新手常误以为“建了新 buffer 就不用管默认的”,结果两个 buffer 加起来远超物理内存。
- 命名 buffer 必须显式用
CACHE INDEX table_name IN hot_cache绑定表,否则索引仍走默认 buffer - 命名 buffer 大小设为 0 会释放内存,但默认 buffer 的
key_buffer_size仍生效,两者不能互相抵消 - 除非你有明确的冷热分离需求(比如高频访问的 MyISAM 表 + 低频归档表),否则没必要搞多个 buffer,维护成本高且易出错
.MYI)本身是静态结构,它的总大小才是硬约束。算出来是 320MB,你就配 256M,而不是看服务器有 64GB 内存就填 16G —— 多出来的那 15.7GB 不会产生任何收益,只会让系统更脆。











