mysql临时表性能骤降主因是内存转磁盘,需监控created_tmp_tables与created_tmp_disk_tables比例超5%即预警;须同步调大tmp_table_size和max_heap_table_size;隐式临时表无法干预,应优化sql减少依赖。

MySQL临时表性能掉得快,往往不是因为用了它,而是它悄悄从内存掉到了磁盘——这个切换无声无息,但查询延迟可能翻10倍。关键不在“要不要用”,而在“怎么让它稳住内存里”。
查清是不是真在用磁盘临时表
别光看EXPLAIN里有没有Using temporary,那只是说明优化器想建临时表,不等于它真落盘了。真正要看的是运行后的状态变量:
-
Created_tmp_tables:总共建了多少个临时表(内存+磁盘) -
Created_tmp_disk_tables:其中多少个被迫写磁盘了
如果后者占前者比例超过5%,就得动手了。执行完可疑SQL后立刻运行:
SHOW STATUS LIKE 'Created_tmp%';对比两个值。更准的做法是开
performance_schema,查events_statements_summary_by_digest定位高频触发者。
为什么调大tmp_table_size没用
常见误区:只改tmp_table_size,忘了max_heap_table_size。MySQL取两者中**较小值**作为单个内存临时表上限。多设一个等于白设。
- 两者必须同步调大,比如都设为256M
- 但光调大没用:含
TEXT、BLOB、JSON字段的查询,哪怕只有一行,也会强制走磁盘 -
ORDER BY或GROUP BY字段太宽(如VARCHAR(500)),或类型不一致(UNION各分支字段宽度不同),也会绕过内存直接落盘
显式建临时表时该选ENGINE=InnoDB还是MEMORY
手动建CREATE TEMPORARY TABLE时,别迷信MEMORY更快。它有硬伤:
- 不支持
TEXT/BLOB,一用就报错或静默降级 - 只支持
HASH和BTREE索引,且HASH不能范围查询 - 表级锁,高并发写入容易卡住
推荐默认用ENGINE=InnoDB:
- 支持事务、行锁、崩溃恢复
- 能建联合索引,后续
JOIN或WHERE可走索引 - 即使数据量大,也比
MEMORY因类型不兼容而失败强
示例:
CREATE TEMPORARY TABLE tmp_user_stats (<br> user_id BIGINT PRIMARY KEY,<br> login_count INT,<br> last_login DATETIME<br>) ENGINE=InnoDB;
隐式临时表没法加索引,只能靠SQL改写
优化器自建的临时表(即EXPLAIN里出现Using temporary那种),你完全没法干预——不能建索引,不能改引擎,不能加提示。唯一办法是让SQL本身少依赖它:
- 把
WHERE条件尽量推到子查询最外层,避免在临时表上全量GROUP BY -
ORDER BY字段必须有索引覆盖,否则必然触发Using filesort+ 临时表 - 用
UNION ALL代替UNION,除非真需要去重 - 派生表(
FROM (SELECT ...))和CTE(WITH)默认物化,考虑改写为JOIN或提前过滤
最易被忽略的一点:字符集不一致会引发隐式转换,导致索引失效,间接迫使优化器建临时表。确保关联字段的CHARACTER SET和COLLATION完全一致。











