type、key、rows、extra 四列是 explain 核心:type=all 或 index 表示索引失效;key 为空或非预期说明索引未命中;rows 远超预期表明扫描失控;extra 出现 using filesort/temporary 需优化排序或分组。

直接看 EXPLAIN 输出但不知道哪列该盯、哪行要警觉?不是你没看懂,是没对齐 MySQL 的判断逻辑——type、key、rows、Extra 这四列才是真命脉,其他字段基本可略过。
type 字段值为 ALL 就等于没走索引
这是最常被忽略的“红灯”。ThinkPHP 里一个看似干净的 where('user_id', $uid),如果 user_id 没建索引,或类型不匹配(比如数据库是 INT,PHP 传了字符串 '123'),type 就是 ALL。
- 别信 buildSql() 生成的 SQL 看着短就安全;必须拿
getLastSql()的结果去 MySQL 执行EXPLAIN -
type = index也不理想,它表示全索引扫描,和全表扫性能接近,常见于SELECT *+ 覆盖索引缺失 -
type = range是合理范围查询的标志,但若后面字段无法复用联合索引(如WHERE a > 1 AND b = 2,索引是(a, b)),b实际不走索引
key 为空或不是预期索引名,说明索引失效了
key 列显示 MySQL 实际选用的索引。为 NULL 或名字不对,基本等于白建。
- ThinkPHP 中用了
whereRaw('DATE(created_at) = ?'),哪怕created_at有索引,key也必为NULL——函数操作直接废掉索引 - 联合索引
(status, category_id),但查询只写了where('category_id', $cid),key仍为NULL:最左前缀没命中 - 大小写敏感表名/字段名(尤其在 Linux 环境),ThinkPHP 配置里写
user_id,但实际字段是UserID,也会导致索引不被识别
rows 值远超预期数据量,说明扫描成本失控
rows 是 MySQL 预估的扫描行数,不是返回行数。它暴增,往往意味着条件没过滤住、索引没生效,或统计信息过期。
- 查 10 条记录,
rows显示 50000?立刻检查type和key,八成是ALL或index - ThinkPHP 分页用
limit 10 offset 10000,rows会随 offset 增大而飙升——这不是 bug,是 MySQL 的天然限制,得换游标分页或覆盖索引优化 - 执行
ANALYZE TABLE users更新统计信息,有时能让rows更准,避免误判
Extra 里出现 Using filesort 或 Using temporary 就得改排序逻辑
这两个提示代表 MySQL 不得不额外做排序或临时表,I/O 和内存开销陡增。
-
order('name desc')但name不在 WHERE 条件索引中?Extra必现Using filesort - 联合索引是
(user_id, created_at),但查询是where('user_id', $uid)->order('created_at desc')→ OK;换成order('id desc')→Using filesort(id没进索引) -
group('category_id')+having('count(*) > 10'),若category_id无索引,Extra出Using temporary
真正卡点不在看懂字段定义,而在把 EXPLAIN 输出和 ThinkPHP 的链式调用一一对应上:哪一行 PHP 代码触发了函数操作,哪个闭包嵌套破坏了最左前缀,哪次 order 调用悄悄绕过了索引。不比对,优化就是蒙眼走路。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











