MySQL升级后启动变慢大概率是table_open_cache不足,尤其分区表多时会反复打开/关闭表文件;需按实际分区实体数而非逻辑表数设置,并同步调大open_files_limit和table_open_cache_instances,否则启动将陷入“开一张、挤一张”恶性循环。

MySQL 升级后启动变慢,大概率是 table_open_cache 不够用了,尤其当分区表数量多、又没调大该参数时,会反复打开/关闭表文件,卡在初始化阶段。
为什么升级后突然变慢?分区表会让 Opened_tables 暴涨
MySQL 5.7 及以后版本对分区表的元数据加载更严格,每个分区在启动时都可能被当作独立表处理(尤其使用 innodb_file_per_table=ON 时)。比如一张按月分区的表有 60 个分区,实际可能触发 60 次表打开操作 —— 这些都会计入 Opened_tables,并争抢 table_open_cache 空间。
-
Opened_tables在启动过程中飙升(可查 error log 或启动后立刻执行SHOW GLOBAL STATUS LIKE 'Opened_tables';) -
Open_tables接近甚至等于当前table_open_cache值,说明缓存已满,新表只能“挤掉旧表”再加载 - 系统日志里出现大量
Could not open table或Failed to open table(非错误,但属警告级高频日志)
怎么设合适的 table_open_cache 值?别只看总表数
分区表不是“一张表”,而是 N 张物理表(.ibd 文件),所以不能按库中“逻辑表数量”估算,得按“实际可能并发访问的分区实体数”来算。例如:分库分表 + 每库 100 张分区表 × 每张 48 个分区 → 单实例潜在活跃分区实体 ≈ 4800+。
- 先临时验证:启动后立刻运行
SET GLOBAL table_open_cache = 8192;(需有 SUPER 权限),再观察后续查询是否还频繁触发Table_open_cache_overflows - 查真实压力:执行
SHOW GLOBAL STATUS LIKE 'Table_open_cache%';,重点关注Table_open_cache_overflows是否持续增长 —— 这个值非零就说明缓存正在被迫淘汰 - 保守起步值:取
max_connections × (平均单条 SQL 涉及表数 + 分区表平均分区数 ÷ 2),例如max_connections=500,常见查询连 3 张表,主业务表平均 32 个分区 → 建议从500 × (3 + 16) = 9500开始试
必须同步调的两个配套参数
table_open_cache 不是孤立参数,设大了不配好底层资源,MySQL 启动时反而会失败或卡死。
-
open_files_limit必须 ≥table_open_cache + max_connections × 2(每个连接至少占 1~2 个额外 fd),否则 MySQL 启动时会静默截断table_open_cache到可用 fd 数以下 —— 查SHOW VARIABLES LIKE 'open_files_limit';就知道它是不是被压低了 -
table_open_cache_instances建议设为 16(默认值)或 32,避免高并发下多个线程争同一 cache 实例锁;如果table_open_cache> 4000,table_open_cache_instances至少设为 16,否则Table_open_cache_overflows会因单实例超限而激增 - OS 层也要跟上:在
/etc/security/limits.conf里给mysql用户加soft nofile 65535和hard nofile 65535,否则 MySQL 读不到足够 fd
启动慢问题常被忽略的细节
很多人改完配置重启还是慢,是因为没意识到:MySQL 启动时会预热所有表(尤其是 InnoDB),而分区表的 frm + ibd + par 文件都要逐个检查校验 —— 这个过程完全依赖 table_open_cache 容量和 fd 资源。哪怕你后面把参数调对了,如果启动时已经因 fd 不足 fallback 到极小缓存值,整个初始化流程就会陷入“开一张、挤一张、再开一张”的恶性循环,耗时呈指数增长。
真正有效的做法是:先确保 OS 层 ulimit -n 对 mysql 进程生效,再在 my.cnf 里写死 open_files_limit 和 table_open_cache,最后用 mysqld --initialize-insecure --datadir=... --verbose 模式手动跑一次冷启动,观察 error log 里 “Starting crash recovery” 到 “Ready for connections” 之间有没有卡在 “Opening tables…” 阶段。


















