调大 tmp_table_size 能缓解索引失效,是因为它使更多临时表保留在内存(MEMORY 引擎),而 MEMORY 表支持索引,避免磁盘临时表(MyISAM/InnoDB)因不继承原表索引导致的性能下降。

为什么调大 tmp_table_size 能缓解索引失效?
MySQL 在执行 GROUP BY、ORDER BY、DISTINCT 等操作时,若结果集过大或字段含 TEXT/BLOB,会把中间结果写入磁盘临时表(MyISAM 或 InnoDB),而磁盘临时表不继承原表索引 —— 这就是“索引失效”的真实来源。调大 tmp_table_size(配合 max_heap_table_size)能让更多临时表保留在内存中(MEMORY 引擎),而 MEMORY 表支持哈希/ B-tree 索引,可加速后续排序或去重。
但注意:tmp_table_size 仅控制单个查询的内存临时表上限;它不改变原 SQL 的执行计划,也不修复缺失的 WHERE 条件索引。
tmp_table_size 和 max_heap_table_size 必须同步调整
MySQL 使用二者中的较小值作为内存临时表大小上限。如果只改 tmp_table_size,而 max_heap_table_size 仍为默认 16MB,那实际生效的还是 16MB。
- 在
my.cnf中需同时设置:tmp_table_size = 256M max_heap_table_size = 256M
- 动态修改需两条语句都执行:
SET SESSION tmp_table_size = 268435456; SET SESSION max_heap_table_size = 268435456;
- 修改后检查是否生效:
SHOW VARIABLES LIKE 'tmp_table_size';和SHOW VARIABLES LIKE 'max_heap_table_size';结果必须一致
怎么确认是不是临时表导致的性能问题?
不能只看慢日志里有没有“Using temporary”,得结合 EXPLAIN 和状态变量交叉验证:
-
EXPLAIN输出中出现Using filesort+Using temporary组合,大概率触发了磁盘临时表 - 执行前后对比:
SHOW STATUS LIKE 'Created_tmp_disk_tables';增量明显上升,说明落地磁盘了 -
SHOW STATUS LIKE 'Created_tmp_tables';是总临时表数,差值可算出内存表占比 - 注意:即使
Created_tmp_disk_tables = 0,也不代表没用临时表 —— 只是全在内存里
调大参数后仍慢?这些点常被忽略
单纯堆内存不是万能解。以下情况即使 tmp_table_size 足够大,依然会强制走磁盘临时表:
- 查询中包含
TEXT、BLOB字段(哪怕只是SELECT *多选了一个没用的description TEXT) -
GROUP BY或ORDER BY的字段存在非确定性排序规则(如utf8mb4_0900_as_cs下的大小写敏感比较,可能绕过索引排序能力) - 使用了
UNION且各子查询的列类型不一致(触发隐式转换,破坏内存表条件) -
tmp_table_size是 SESSION 级变量,某些连接池(如 Druid)会复用连接并保留旧 session 设置,需确认应用侧是否真正生效
真正治本的方式,仍是收敛查询字段、补全 WHERE 索引、拆分复杂聚合逻辑 —— tmp_table_size 只是缓冲带,不是替代索引的方案。


















