出现Using temporary或Using filesort说明MySQL正使用磁盘临时表或文件排序,需立即优化;应检查type字段是否为ALL/index、key_len是否匹配,并按GROUP BY顺序创建联合索引,避免在GROUP BY中使用函数。

EXPLAIN里出现Using temporary就该动手了
只要执行计划的Extra列里有Using temporary或Using filesort,基本等于告诉你要优化了。这不是警告,是确诊书——MySQL正把分组过程挪到磁盘临时表上跑,I/O一上来,查询时间就从毫秒跳到秒级甚至更久。
实操建议:
- 用
EXPLAIN FORMAT=TRADITIONAL SELECT ... GROUP BY ...确认这两个提示是否存在 - 检查
type字段:如果是ALL或index(而非ref/range),说明没走有效索引 - 核对
key_len:比如字段是VARCHAR(255)但只用了前10个字节,key_len却显示765,说明索引定义和实际查询不匹配
建索引不是加单列,而是按GROUP BY顺序拼联合索引
给user_id单独建索引,对GROUP BY user_id, status几乎没用。真正起效的是最左前缀匹配的联合索引,且字段顺序必须和GROUP BY子句完全一致。
实操建议:
- 例如
GROUP BY user_id, status→ 建INDEX idx_group (user_id, status) - 如果还有
WHERE status = 'active',优先建INDEX idx_where_group (status, user_id),让过滤和分组一步完成 - 若
SELECT里还包含AVG(salary),可扩展为(status, user_id, salary),形成覆盖索引,避免回表
别在GROUP BY里套函数,DATE(created_at)这种写法直接废掉索引
GROUP BY DATE(created_at)会让所有索引失效,MySQL只能全表扫描再计算日期值。这不是语法问题,是执行路径被彻底堵死。
实操建议:
- 提前生成冗余字段,比如
created_date DATE,并为其建索引 - 用范围条件替代:先
WHERE created_at >= '2024-01-01' AND created_at 缩小数据量,再按<code>created_date分组 - MySQL 8.0+虽支持函数索引,但
DATE()这类函数索引仍受限于表达式确定性,生产环境慎用
tmp_table_size不够时,Copying to tmp table on disk会拖垮性能
当内存临时表撑不住,MySQL会落盘成MyISAM临时表,SHOW PROCESSLIST里看到Copying to tmp table on disk就是信号。这不是配置调大就能解决的,而是逻辑设计已到临界点。
实操建议:
- 先调
tmp_table_size和max_heap_table_size到合理值(如64M–256M),但不能无限制堆高 - 更关键的是控制输入行数:确保
WHERE过滤足够激进,比如WHERE region = '华东' AND status = 'paid'后再分组 - 高基数字段(如
order_no、ip)直接GROUP BY极易触发磁盘临时表,应先降维:IP转地区、订单号取前缀哈希等
GROUP BY字段的DISTINCT数量和NULL占比,比调tmp_table_size管用得多。


















