type=all表示全表扫描,即mysql逐行读取整张表,数据量超十万时查询显著变慢或超时;常见原因有where条件使用函数、隐式类型转换或字段无索引。

EXPLAIN 显示 type=ALL 就是全表扫描
看到 type 列是 ALL,基本等于没走索引。MySQL 正在一行行读完整张表,数据量一过十万,查询就明显变慢甚至超时。
常见诱因:WHERE 条件用了函数(比如 WHERE YEAR(created_at) = 2023)、隐式类型转换(user_id 是 VARCHAR 却传了数字)、或者条件字段根本没建索引。
- 先用
SHOW CREATE TABLE <code>table_name确认字段类型和现有索引 - 检查
WHERE右侧值是否与字段类型严格一致(字符串加引号、数字不拼接) - 避免在索引列上使用函数或表达式,改写为可命中索引的形式(例如把
YEAR(created_at)换成created_at BETWEEN '2023-01-01' AND '2023-12-31')
key 列为空或显示 NULL 表示索引被忽略
key 列显示 NULL,说明优化器评估后主动放弃了索引——不是没建,而是“觉得不划算”。典型场景包括:表太小(gender 只有 'M'/'F')、或者 WHERE 条件返回结果占比过高(超过约 20%)。
这时候强行加 FORCE INDEX 往往适得其反,反而让执行计划更僵化。
- 用
SELECT COUNT(*) FROM <code>table_nameWHEREcondition估算筛选比例 - 对低区分度字段(如状态位、开关标志),优先考虑组合索引中把它放后面,而非单独建索引
- 如果确实需要按低区分度字段查,且数据分布极不均匀(比如 99% 是 'active',只查那 1% 的 'deleted'),可以给该值建函数索引(MySQL 8.0+)或冗余字段索引
Extra 列出现 Using filesort 或 Using temporary 很危险
这两个提示意味着 MySQL 在内存或磁盘上额外做了排序或临时表操作,尤其是当 rows 值很大时,I/O 和 CPU 开销会指数级上升。
根本原因通常是 ORDER BY 或 GROUP BY 字段没被索引覆盖,或者索引顺序和排序需求不一致(比如索引是 (a, b),但查询 ORDER BY b)。
- 确保
ORDER BY字段出现在联合索引最左前缀,且方向一致(ASC/DESC要匹配,MySQL 8.0+ 才支持混合方向) - 用
SELECT ... ORDER BY ... LIMIT时,如果rows远大于LIMIT数,说明排序成本极高,优先优化索引覆盖 -
Using temporary在涉及DISTINCT、GROUP BY或子查询时高频出现,检查是否能通过调整索引把分组/去重逻辑下推到存储层
ref 列显示 const 或 func 说明索引用了但不精准
ref 是 const 通常表示等值查询命中了主键或唯一索引,没问题;但如果是 func,说明用了函数结果做索引查找,往往意味着隐式转换或计算列,稳定性差。
例如 user_id 是 VARCHAR(32),而查询写了 WHERE user_id = 123(没加引号),MySQL 会把每条字符串转成数字比对,索引失效风险高,且可能误匹配('123abc' 也会被转成 123)。
- 所有字符串字段的
WHERE条件必须显式加单引号 - 用
SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS核对字段类型,别依赖印象 - 开发环境开启
sql_mode=STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,让隐式转换直接报错,而不是静默出错
真正难调的不是“有没有索引”,而是“为什么有索引却不用”——执行计划里每个字段都在说人话,只是得习惯听。











