Open_tables与table_open_cache比值≥0.95说明缓存常满,需调大;比值长期<0.7则浪费内存;须同步配置table_open_cache_instances为CPU核心数且≤16,并确保table_open_cache≤open_files_limit×0.8。

Open_tables 接近 table_open_cache 就说明缓存不够用
直接看 Open_tables 和 table_open_cache 的比值,比值 ≥ 0.95 就基本可以断定缓存常满。这时 MySQL 不得不频繁淘汰旧表、打开新表,触发大量文件系统调用(.ibd、.frm),CPU 花在 open/close 上明显变多。
别只盯着 Opened_tables 单独飙升就调参——如果 Open_tables 长期只有几十或一两百,哪怕 Opened_tables 已破百万,问题大概率出在临时表滥用、短连接反复建表或 HANDLER 语句上,不是缓存大小的问题。
验证命令就这三行,必须一起跑:
SHOW GLOBAL STATUS LIKE 'Open%tables%'; SHOW VARIABLES LIKE 'table_open_cache'; SHOW VARIABLES LIKE 'open_files_limit';
table_open_cache 值不能超过 open_files_limit
MySQL 启动时会把 table_open_cache 截断到 open_files_limit 以内,且不报错。你设了 4000,但 open_files_limit 是 2048,实际生效的还是 2048 —— 然后你还在纳闷“为什么调了没用”。
安全设置区间要留余量:
-
table_open_cache ≤ open_files_limit × 0.8:预留至少 20% 给日志、临时表、复制线程等 - 4G 内存机器常见起点是
2048;几十张表 + 低并发,512更稳,避免内存浪费 - 别按
max_connections × 平均每条 SQL 表数硬算——OLTP 场景下这个公式高估严重,实际峰值Open_tables才是可靠依据
必须同步改 table_open_cache_instances
默认 table_open_cache_instances = 1,所有线程抢同一把 mutex,高并发下容易卡在等待队列里。你看到 SHOW ENGINE INNODB STATUS 里一堆 wait array slots,八成就是它。
这个参数比 table_open_cache 本身还容易被忽略:
- 设为物理 CPU 核心数(上限 16),比如 8 核机器就配
8 - 它和
table_open_cache是乘积关系:总缓存容量 =table_open_cache × table_open_cache_instances,但分片后锁竞争大幅下降 - 云数据库(如 RDS)通常已自动调优,自建 MySQL 务必手动检查并显式配置
调完必须观察 Open_tables / table_open_cache 是否稳定在 0.7–0.95
调大之后不是万事大吉。如果比值长期低于 0.7,说明缓存设太大,白白占内存;高于 0.95 则说明淘汰压力仍在,还得再调。
另外两个坑要注意:
- 应用里用了
HANDLER语句?它绕过缓存,独占表对象,长期不释放,Open_tables会被撑高,但调table_open_cache没用 - 连接池泄漏或未关闭连接?每个活跃连接都可能持有若干打开表,推高
Open_tables,掩盖真实瓶颈
真正有效的调优,永远是从状态指标出发,而不是从“别人说该设多大”出发。缓存够不够,MySQL 自己说了算,你只要读懂它的状态就行。


















