explain中出现using temporary说明mysql放弃索引有序性,改用临时表分组,性能已严重下降;主因包括group by与索引最左前缀不匹配、非分组列未被索引覆盖、where含范围条件中断索引、隐式类型转换等。

EXPLAIN 里看到 Using temporary 就该警觉
只要 EXPLAIN 结果的 Extra 列出现 Using temporary,基本可以断定 GROUP BY 正在用内存或磁盘临时表做分组,性能已经掉坑里了。这不是“有点慢”,而是 MySQL 放弃了索引天然有序性,退回到全量数据搬运+重建分组结构的老路。
常见诱因包括:
-
GROUP BY a, b,但索引是(b, a)或只有(a)—— 最左前缀不匹配,索引无法支撑分组顺序 - SELECT 中用了非分组列(如
SELECT status, MAX(note) FROM t GROUP BY status),而索引只建了(status),没包含note,MySQL 认为回表代价高,干脆全扫+临时表 - WHERE 条件含范围查询(如
created_at > '2024-01-01')且放在联合索引中间,导致后续 GROUP BY 字段的索引失效 - 隐式类型转换:比如
user_id = '123'(字段是BIGINT),字符串和数字比较触发转换,整条索引失效
phpMyAdmin 里执行 EXPLAIN 的正确姿势
别直接把慢 SQL 粘贴进「SQL」标签页点执行——尤其是带 UPDATE、DELETE 或没加 LIMIT 的语句。先手动在语句最前面加上 EXPLAIN,再运行。
例如原 SQL 是:
SELECT category, COUNT(*), AVG(price) FROM products WHERE status = 'active' GROUP BY category;
就在 phpMyAdmin 的 SQL 输入框里写:
EXPLAIN SELECT category, COUNT(*), AVG(price) FROM products WHERE status = 'active' GROUP BY category;
重点盯三列:type(是否 ALL 或低效的 index)、key(实际用了哪个索引)、Extra(有没有 Using temporary 或 Using filesort)。
怎么确认是不是覆盖索引生效了
覆盖索引不是“建了索引就行”,而是要让 MySQL 完全不用回表查数据。判断标准很硬:
-
EXPLAIN中key显示用了某个索引 -
Extra里没有Using temporary和Using filesort - SELECT 所有字段(含 GROUP BY 列、聚合函数依赖的非分组列)都落在该索引定义中
比如 SELECT category, COUNT(*), MAX(note) FROM t GROUP BY category,索引至少得是 (category, note);只建 (category) 不算覆盖,因为 MAX(note) 还得回表捞值。
MySQL 5.7 不支持函数索引,GROUP BY DATE(created_at) 必须靠生成列 + 索引;8.0 可直接建 INDEX (DATE(created_at))。
别被 ORDER BY NULL 欺骗
ORDER BY NULL 能干掉 Using filesort,但前提是 Using temporary 已经消失。如果 Extra 同时出现两个,加 ORDER BY NULL 几乎没用——排序只是表层问题,临时表才是根子。
更要小心客户端干扰:SQLyog 会偷偷优化掉某些排序逻辑,导致本地快、服务器上慢。你看到的“加了 ORDER BY NULL 变快了”,可能只是客户端在帮你省事,不是 MySQL 真变快了。
真正该死盯的是 Using temporary:它一出现,说明分组逻辑本身低效,调参、加 ORDER BY NULL、改 tmp_table_size 都是缓兵之计,治标不治本。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











