thread_cache_size 是 MySQL 服务器端的线程缓存池,用于缓存已断开的客户端连接线程,避免重复创建/销毁线程的开销。


一、核心作用:减少线程创建开销

工作原理对比

无缓存thread_cache_size = 0):

客户端连接 → 创建新线程(malloc + pthread_create)→ 执行查询 → 销毁线程

有缓存thread_cache_size > 0):

客户端连接 → 复用缓存线程 → 执行查询 → 线程归还缓存池

性能差异:创建/销毁线程需要 内存分配 + 系统调用,在高并发短连接场景下消耗显著。


二、关键监控指标

SHOW STATUS LIKE 'Threads%';

指标

含义

健康值

Threads_connected

当前活跃连接数

随业务波动

Threads_running

正在执行查询的线程数

通常 < 20

Threads_created

自启动以来创建的线程总数

增长应缓慢

Threads_cached

当前缓存池中的空闲线程数

接近配置值

核心诊断公式

-- 线程缓存命中率(应 > 95%)
SELECT 
  (1 - Threads_created / Connections) * 100 AS thread_cache_hit_rate
FROM (SELECT 
        SUM(IF(VARIABLE_NAME='Threads_created', VARIABLE_VALUE, 0)) AS Threads_created,
        SUM(IF(VARIABLE_NAME='Connections', VARIABLE_VALUE, 0)) AS Connections
      FROM performance_schema.global_status) t;

三、配置方法

1. 动态调整(推荐)

-- 立即生效,无需重启
SET GLOBAL thread_cache_size = 50;

2. 永久配置

[mysqld]
# 根据公式计算
thread_cache_size = 50

四、科学计算:黄金公式

公式推导

thread_cache_size = max_connections × (1 - thread_cache_hit_rate_target)

简化经验法则

场景

推荐值

连接池应用 (HikariCP)

50 ~ 100

短连接 PHP/无连接池

100 ~ 200

max_connections < 100

20 ~ 50

max_connections > 1000

200 ~ 300

核心原则 :缓存大小 = 并发连接峰值 × 20% 。因为通常只有 20% 的连接会频繁断开/重建。


五、最佳实践

✅ 推荐配置(覆盖 90% 场景)

[mysqld]
max_connections = 500
thread_cache_size = 50        # 不是 500!50 足够

# 关联配置
thread_stack = 256K           # 单个线程栈大小

❌ 常见误区

  1. 等于 max_connections :浪费内存,缓存过多闲置线程。

  2. 设为 0 :短连接场景性能急剧下降。

  3. 从不监控 :Threads_created 持续增长却未察觉。


六、真实案例:短连接性能优化

场景:PHP 应用(无连接池)

优化前:

thread_cache_size = 0

监控

SHOW STATUS LIKE 'Threads_created';  -- Uptime 1小时:50000
SHOW STATUS LIKE 'Connections';      -- Uptime 1小时:50000
-- 命中率 = (50000-50000)/50000 = 0%

优化后

thread_cache_size = 100

监控(1小时后):

SHOW STATUS LIKE 'Threads_created';  -- 100
SHOW STATUS LIKE 'Connections';      -- 50000
-- 命中率 = (50000-100)/50000 = 99.8%

性能提升:QPS 提升 10~15%,CPU 消耗降低。


七、常见问题与排查

问题 1:Threads_created 持续增长

-- 检查是否连接池配置不当
SHOW PROCESSLIST;
-- 大量 TIME 很短的连接 => 短连接泛滥

解决方案

  • 应用层引入连接池

  • 调大 thread_cache_size

问题 2:内存占用过高

-- 估算线程缓存内存(线程栈 + 元数据)
SELECT @@thread_cache_size * @@thread_stack / 1024 / 1024 AS cache_memory_mb;

问题 3:与线程池插件冲突

# 若使用线程池(如 Percona / MySQL Enterprise)
[mysqld]
thread_handling = pool-of-threads
thread_cache_size = 0  # 线程池会接管,此参数失效

八、版本差异

版本

默认值

说明

MySQL 5.7

-1(自动计算)

公式:8 + (max_connections / 100)

MySQL 8.0

-1(自动计算)

公式:max_connections + 1(但更保守)

推荐设置

手动设置为 50~100

不要依赖自动计算

8.0 自动计算的陷阱

-- 查看当前自动值
SHOW VARIABLES LIKE 'thread_cache_size';  -- 可能是 -1

-- 实际生效值(运行时计算)
SELECT @@global.thread_cache_size;  -- 可能是 11

结论:自动值偏小,短连接场景下性能不佳,务必手动设置


九、完整配置示例

[mysqld]
# 连接与线程配置
max_connections = 500
thread_cache_size = 50

# 关联参数
thread_stack = 256K
wait_timeout = 600
interactive_timeout = 600

# 8.0+ 数据字典缓存配套
table_open_cache = 6500
table_definition_cache = 2000

十、总结与一句话决策

配置决策树

是短连接吗? → 是 → thread_cache_size = 100
            ↓ 否
            使用连接池? → 是 → thread_cache_size = 50
                       ↓ 否
                       调大 wait_timeout,减少频繁断开

核心记忆点

  • Threads_created 增长快 = 缓存太小

  • 命中率 > 95% = 配置合理

  • 50 ~ 100 覆盖 90% 场景

  • 8.0+ 务必手动设置,别用自动值

一句话:让 Threads_cached 稳定在 thread_cache_size 的 80% 以上,且 Threads_created 不再快速增长。