opened_tables每秒增长超50且open_tables/table_open_cache>0.95,表明缓存不足;需同步检查open_files_limit和table_definition_cache,并将table_open_cache_instances设为8~16以降低锁争用。

查 Opened_tables 值是否异常高
如果 Opened_tables 每秒增长几十甚至上百,说明 MySQL 频繁打开物理表文件(.ibd 或 .MYD),而不是复用缓存中的表句柄。这是 table_open_cache 不足的直接信号。
执行:SHOW GLOBAL STATUS LIKE 'Opened_tables';
再间隔 10 秒执行一次,计算差值。若差值 > 50/10s,基本可以判定缓存偏小。
- 同时观察
Open_tables/table_open_cache比值:理想应 ≤ 0.95,超过说明缓存常满 - 注意
Opened_tables是累计值,不能单看绝对值;重点看增量速率 - 如果业务有大量 JOIN 查询(尤其涉及 5 张以上表),每个连接打开的表数会翻倍,
Opened_tables上涨更快
设值不能只看 max_connections
table_open_cache 不是 max_connections 的简单倍数。它取决于「单个查询最多打开几张表」+「并发连接中同时活跃的查询数」。
例如:100 个连接,平均每个查询关联 4 张表,但同一时刻只有约 30% 连接在执行 SQL,则合理值 ≈ 100 × 4 × 0.3 ≈ 120 —— 再加 20% 余量,设为 150 即可。盲目设成 2000 可能触发 OS 文件描述符耗尽。
- MyISAM 表每张占 2 个文件描述符(数据 + 索引),InnoDB 表通常只占 1 个(
.ibd) - 必须同步检查
open_files_limit:执行SHOW VARIABLES LIKE 'open_files_limit';,确保它 ≥table_open_cache× 1.2(留出临时表、日志等开销) - Linux 下用
lsof -u mysql | wc -l实时查看 mysqld 进程已打开文件数,避免接近系统 limit
调整后必须验证 Open_tables / Opened_tables 比率
调大 table_open_cache 后,关键指标不是 Open_tables 变多,而是 Opened_tables 增速明显下降。真正有效的阈值,是让 Open_tables / Opened_tables ≥ 0.85。
- 这个比值反映「缓存命中率」:0.85 意味着 85% 的表打开请求直接命中缓存,不用碰磁盘
- 如果比值卡在 0.6 以下,即使把
table_open_cache设到 4096 也没用——可能是因为table_definition_cache太小,导致表定义反复加载,间接拖慢表打开流程 -
table_open_cache_instances建议设为 8~16(而非默认 1),尤其当并发线程 > 200 时,能降低 cache 访问锁争用
别忽略 table_definition_cache 的协同影响
table_open_cache 管的是「打开的表实例」,而 table_definition_cache 管的是「表结构定义」。后者太小会导致每次打开表前都要重新解析 .frm 或 INFORMATION_SCHEMA,拖慢整个打开流程,让 table_open_cache 优化失效。
- 执行
SHOW GLOBAL STATUS LIKE 'Open_table_definitions';和Opened_table_definitions,若后者增长快,就该调大table_definition_cache - 推荐值:设为数据库中总表数的 1.5 倍(例如有 800 张表,设 1200)
- 它和
table_open_cache共享文件描述符配额,两者要一起评估,不能只盯一个
open_files_limit 是否真生效——MySQL 启动时会取 ulimit -n 和配置文件中 open_files_limit 的较小值,且很多 systemd 环境下需要额外配置 LimitNOFILE 才能突破默认 4096。











