type=all 表示全表扫描,是查询性能瓶颈的典型征兆,因mysql无法使用索引而逐行读取整表,常见于缺失索引、函数包裹索引列或隐式类型转换等情况。

EXPLAIN 输出里 type=ALL 是什么信号
这代表全表扫描,是最容易拖慢查询的典型征兆。MySQL 没法用索引定位数据,只能一行行读完整张表。哪怕只有几万行,一旦并发上来或磁盘 I/O 偏高,响应就明显卡顿。
常见诱因包括:WHERE 条件字段没建索引、用了函数包裹索引列(比如 WHERE YEAR(created_at) = 2023)、隐式类型转换(user_id 是 VARCHAR,但查询写了 WHERE user_id = 123)。
实操建议:
- 对
EXPLAIN中type为ALL或index的语句,优先检查possible_keys和key列是否为空 - 用
SHOW CREATE TABLE确认字段类型和现有索引,注意联合索引顺序是否匹配查询条件顺序 - 避免在索引字段上做运算或函数调用;改写成
WHERE created_at >= '2023-01-01' AND created_at
Extra 列出现 Using filesort 或 Using temporary 怎么办
这两个提示说明 MySQL 正在内存或磁盘上额外排序或临时建表——不是语法错,但意味着 ORDER BY、GROUP BY 或 DISTINCT 没走索引优化路径。
比如 ORDER BY status, created_at,但只对 status 建了单列索引,MySQL 就得取出所有匹配行再排序。
实操建议:
-
Using filesort:确认ORDER BY字段是否被包含在联合索引的最左前缀中,且顺序一致;如需按status, created_at排序,索引应为(status, created_at) -
Using temporary:检查是否必须用GROUP BY配合非索引字段聚合;尝试把聚合字段也加入联合索引,或改用覆盖索引减少回表 - 临时表大小受
tmp_table_size和max_heap_table_size控制,但治标不治本,重点还是索引设计
key_len 值比预期小,说明什么
key_len 显示 MySQL 实际用到的索引字节数。如果联合索引是 (a, b, c),但 key_len 只显示 a 对应的长度,说明只用到了索引的第一部分。
原因通常是 WHERE 条件没包含后续字段,或者用了范围查询(如 a = 1 AND b > 10),导致 c 无法继续使用索引。
实操建议:
- 对照
SHOW CREATE TABLE查每个字段的字节长度(比如VARCHAR(50)utf8mb4 下最多占 200 字节) - 范围查询(
>,, <code>BETWEEN,LIKE前缀不固定)会让索引“断”在该列,后续字段失效 - 如果业务允许,把高频等值查询字段放在联合索引前面,范围字段放后面
为什么加了索引,EXPLAIN 还显示没用上
索引存在 ≠ 查询会用。MySQL 优化器会根据统计信息估算成本,如果它认为全表扫描更快(比如表很小、或命中率极低),就会跳过索引。
另一个常见原因是查询条件中用了 OR,且只有部分分支有索引;或者 LIKE 以通配符开头(LIKE '%abc')直接让索引失效。
实操建议:
- 用
ANALYZE TABLE更新统计信息,尤其在大批量导入后 - 拆 OR 条件为
UNION(确保各分支都能走索引) - 确认字符集和排序规则一致,跨库 JOIN 时容易因 collation 不匹配导致索引失效
- 用
FORCE INDEX强制走某索引仅作验证,不能长期依赖
真正难的不是看懂 EXPLAIN,而是把执行计划里的每一列和线上实际负载、数据分布、缓存状态串起来判断。比如 rows 预估 1000,实际扫了 50 万行?那大概率是统计信息严重不准,或者查询参数让优化器误判了选择性。











