mysql 8.0 的 table_definition_cache 不再缓存 .frm 文件,而是缓存从 innodb 数据字典表解析的内存结构体;因解析开销大、单表定义内存占用高,旧默认值易致缓存频繁淘汰,引发 opening table 延迟和 dict_operation_lock 争用,需依据 open_table_definitions 和 opened_table_definitions 指标动态调优,并协同调整 table_open_cache 与 open_files_limit。

MySQL 8.0 的数据字典已彻底重构,table_definition_cache 不再缓存 .frm 文件
MySQL 8.0 将数据字典(Data Dictionary)从文件系统(.frm、.par 等)完全迁移到 InnoDB 表中,并常驻内存管理。这意味着 table_definition_cache 的作用对象变了:它不再加载和缓存文本格式的表结构定义,而是缓存从数据字典表中读取并序列化后的内存结构体。
迁移后常见现象是:Opened_table_definitions 突然升高、Open_tables 波动变大、甚至出现 opening table 状态延迟——不是因为缓存小了,而是因为首次访问每张表时需从 InnoDB 数据字典表中解析结构,开销比读 .frm 更重。所以旧版经验(比如“设成和 table_open_cache 一样大”)直接失效。
为什么 table_definition_cache 值在 8.0 下更容易成为瓶颈
新版数据字典结构更复杂,单个表定义占用内存显著增加(尤其带大量列、分区、生成列、JSON 字段或外键的表)。如果该参数仍沿用 5.7 的默认值(如 400 或 1400),而实际库中有 2000+ 张表,就会频繁触发定义缓存淘汰与重载,表现为:
-
Table_open_cache_misses和Opened_table_definitions持续上升 - 慢查询日志里出现大量
Opening table等待(注意:不是锁等待,是定义解析等待) - show processlist 中状态卡在
preparing或checking permissions阶段
这不是并发连接数问题,而是每个连接首次访问某张新表时,都要争抢 dict_operation_lock 并解析定义——此时 table_definition_cache 太小会放大锁争用。
怎么调才靠谱:看指标,不拍脑袋
别按“表总数 × 1.2”这种公式硬算。重点盯两个状态变量:
-
Open_table_definitions:当前缓存中命中的表定义数量,应稳定接近table_definition_cache值的 70%~90% -
Opened_table_definitions:自启动以来重新加载定义的总次数,若每秒增长 > 1–2 次,说明缓存严重不足
实操建议:
- 先执行
SHOW GLOBAL STATUS LIKE 'Open%table%',确认Open_table_definitions是否长期低于table_definition_cache的 50% - 若偏低,逐步调大
table_definition_cache(每次 +512),观察Opened_table_definitions增速是否明显下降 - 必须同步检查
open_files_limit:该值必须 ≥table_open_cache+table_definition_cache+ 预留空间(至少 +1024),否则 MySQL 会静默截断,你改了也白改 - 云数据库(如阿里云 RDS、腾讯云 CDB)通常已预设合理值(常见为 4096 或 8192),但如果你做了跨库逻辑复制或大量临时库切换,仍需单独验证
table_definition_cache 和 table_open_cache 必须协同调,不能只动一个
这两个缓存是解耦但强关联的:前者管“表长什么样”,后者管“这张表的句柄能不能复用”。8.0 下,如果 table_definition_cache 不足,即使 table_open_cache 很大,也会因反复解析定义导致句柄无法有效复用,最终 Opened_tables 照样飙升。
容易被忽略的关键点:
-
table_open_cache_instances默认为 1,高并发下会成为瓶颈——它控制的是表句柄缓存的分片锁,和定义缓存无关,但两者都影响opening table耗时 - DDL 操作(尤其是
ALTER TABLE)在 8.0 中会清空对应表的定义缓存条目,若业务有高频 DDL,table_definition_cache再大也没用,得先收敛 DDL 频率 - 监控时别只看全局值:用
performance_schema.table_handles查具体哪些表被频繁打开/关闭,比泛泛调参更精准











