mysql内部临时表是优化器自动创建的中间结果存储结构,常见于group by、distinct、order by无索引、union及派生表等场景;一旦超出tmp_table_size与max_heap_table_size较小值,或含text/blob等大字段,即强制落盘为磁盘表,引发显著io性能下降。

MySQL 临时表分两类:你主动创建的 CREATE TEMPORARY TABLE,和 MySQL 内部自动创建的“内部临时表”。后者才是性能隐患的主要来源——它不显式出现,但会在执行计划里留下 Using temporary 的痕迹,且一旦落到磁盘,IO 开销会陡增。
哪些 SQL 会触发内部临时表?看 EXPLAIN 就知道
只要 EXPLAIN 输出的 Extra 列里出现 Using temporary,就说明 MySQL 正在用内部临时表。常见触发点有:
-
GROUP BY字段没索引,或索引无法覆盖排序顺序(比如GROUP BY a,b但只有(b,a)索引) -
ORDER BY无法走索引,尤其是多字段排序方向不一致(如ORDER BY x ASC, y DESC) -
DISTINCT或UNION(UNION ALL通常不触发,但UNION要去重) -
FROM子句里的子查询(即派生表),例如SELECT * FROM (SELECT id FROM t WHERE x=1) AS tmp -
JOIN时驱动表结果集太大,且关联条件无索引,优化器可能选择物化右表
为什么临时表会从内存掉到磁盘?
内存临时表不是无限大的。它实际受两个参数中更小的那个限制:tmp_table_size 和 max_heap_table_size。只要临时表数据量超过这个阈值,MySQL 就会把它转成磁盘表(默认引擎是 InnoDB,不是旧版的 MyISAM)。更隐蔽的是,以下情况会直接跳过内存、强制走磁盘:
- 字段含
TEXT、BLOB类型 -
UNION查询中任意列长度 > 512 字节 -
GROUP BY或DISTINCT的列定义长度 > 512 字节 - 使用了
CREATE TEMPORARY TABLE ... ENGINE=InnoDB显式指定磁盘引擎
怎么判断临时表是不是真成了瓶颈?
别猜,查状态变量:
-
SHOW STATUS LIKE 'Created_tmp%';—— 关注Created_tmp_tables(总临时表数)和Created_tmp_disk_tables(磁盘临时表数) - 如果
Created_tmp_disk_tables / Created_tmp_tables > 0.1(即超 10% 落盘),就要警惕 - 配合
slow_query_log+log_queries_not_using_indexes,定位具体哪条 SQL 在拖慢系统
真正麻烦的不是“有没有临时表”,而是“有没有大量磁盘临时表”——它往往意味着查询设计不合理、索引缺失,或者数据模型与访问模式错配。优化时优先考虑加索引、改写 SQL(比如用 CTE 替代派生表),而不是调大 tmp_table_size。











