全表扫描主因是where条件与索引不匹配,而非无索引;包括违反最左前缀原则、索引列上用函数/表达式、使用or/!=/is null等低效操作符,以及未验证explain执行计划。

全表扫描不是“没建索引”才发生,而是 WHERE 条件和现有索引对不上——哪怕索引存在,只要写法踩中任一常见陷阱,MySQL 就会退化为逐行扫描。
WHERE 字段没索引或不满足最左前缀原则
联合索引 (a, b, c) 不是“包含 a、b、c 就能用”,它只对从 a 开始的连续前缀生效。优化器不会跳过中间列去匹配 b 或 c。
-
WHERE a = 1 AND b > 10→ 走索引(a等值 +b范围) -
WHERE b = 10或WHERE c = 'x'→ 全表扫描(a缺失,无法定位起点) -
WHERE a = 1 AND c = 'x'→ 只用上a,c无法跳过b,仍需回表或扫描
确认索引真实存在且有效:运行 SHOW INDEX FROM table_name,别依赖命名猜测;删除冗余单列索引(如已有 (a, b),再单独建 a 索引意义不大)。
WHERE 中用了函数、隐式转换或表达式
MySQL 无法把函数结果反向映射到索引 B+ 树节点,一旦在索引列上做运算,索引立即失效。
-
WHERE YEAR(create_time) = 2024→ 改成WHERE create_time >= '2024-01-01' AND create_time -
WHERE mobile = 13812345678(mobile是VARCHAR)→ 改成WHERE mobile = '13812345678',否则触发隐式转换 -
WHERE price * 1.06 > 100→ 改成WHERE price > 100 / 1.06,把计算移到常量侧 -
WHERE name LIKE '%abc'→ 无法走索引;若业务允许,改用name LIKE 'abc%'或加前缀索引
WHERE 使用了低效操作符:OR、!=、IS NULL、NOT IN
这些操作符本身不具备高效范围定位能力,优化器常判定“扫一遍比走索引还快”,尤其当数据分布均匀时。
-
WHERE status != 0→ 改成WHERE status IN (1, 2, 3)(状态值有限前提下) -
WHERE a = 1 OR b = 2→ 更可靠的是拆成SELECT ... WHERE a = 1 UNION ALL SELECT ... WHERE b = 2,前提是a和b各自有单列索引 -
WHERE col IS NULL→ 即使col有索引,也可能不走;建议设默认值(如0或''),查WHERE col = 0 -
WHERE id NOT IN (1, 2, NULL)→ 右侧含NULL会导致整个条件恒为FALSE,且易全表扫描;优先用NOT EXISTS或重写逻辑
验证是否真走了索引:别信感觉,看 EXPLAIN
执行计划才是唯一真相。重点关注两个字段:key 是否非空、type 是否为 ALL。
-
key为NULL且type是ALL→ 明确全表扫描 -
type是range、ref、const→ 正常走索引 -
Extra出现Using filesort或Using temporary→ 即便走了索引,排序/分组仍可能拖慢性能
复杂查询中,ORDER BY 和 LIMIT 组合也容易误导:如果 WHERE 匹配 100 万行,LIMIT 10 不会减少扫描量,除非索引能直接覆盖排序顺序(比如建 (status, created_at) 联合索引支撑 WHERE status = 1 ORDER BY created_at LIMIT 10)。











