SQL查询为什么全表扫描_索引失效原因总结【教学】

SQL查询全表扫描主因是查询条件未有效触发索引使用。1.对索引列用函数或运算(如YEAR(create_time)=2025);2.LIKE以%开头(如name LIKE '%明');3.隐式类型转换(如VARCHAR字段传数字);4.联合索引未遵循最左前缀原则(如索引(a,b,c)只查b,c)。

SQL查询出现全表扫描,通常是因为数据库优化器没走索引,转而逐行读取整张表——性能会随数据量增长急剧下降。核心问题不在于“有没有建索引”,而在于“查询条件能否有效触发索引的使用”。下面从常见场景出发,说清楚索引为啥失效、怎么避免。

WHERE条件中对索引列做了函数或运算

数据库无法直接用索引定位值,必须先计算每行结果再比对,索引自然被跳过。

  • ❌ 失效写法: WHERE YEAR(create_time) = 2025WHERE price * 1.1 > 100
  • ✅ 推荐写法: 改成范围查询,如 WHERE create_time >= '2025-01-01' AND create_time ;价格比较改写为 WHERE price > 100 / 1.1

模糊查询时LIKE以通配符开头

B+树索引按字典序存储,前缀匹配可快速定位,但%abc这种没有固定前缀,只能全扫。

  • ❌ 失效写法: WHERE name LIKE '%明'WHERE name LIKE '%李%'
  • ✅ 可选方案: 前缀匹配保留索引能力,如 WHERE name LIKE '李%';若必须前后模糊,考虑全文索引(FULLTEXT)或ES等外部检索方案

隐式类型转换导致索引失效

字段是字符串类型,但查询时传了数字;或字段是INT,却用字符串比较——MySQL会自动转换,但索引列被“加工”了,无法命中。

  • ❌ 失效写法: user_idVARCHAR,却写 WHERE user_id = 123(数字);或 statusTINYINT,却写 WHERE status = '1'
  • ✅ 解决方法: 保持类型一致:字符串字段用引号,数值字段别加引号;用 EXPLAIN 查看 type 是否为 ALL,并检查 Extra 列是否含 Using where; Using index

联合索引未遵循最左前缀原则

联合索引 (a, b, c) 实际上只对 a(a,b)(a,b,c) 三种组合高效;跳过左边列(比如只查 bb,c),索引就用不上。

  • ❌ 失效写法: WHERE b = 2 AND c = 3(缺少 a);WHERE a = 1 AND c = 3(跳过 b
  • ✅ 优化建议: 按查询高频模式设计联合索引顺序;必要时补充覆盖索引,如 (a,c) 单独建;用 EXPLAINkey_len 值,判断实际用了索引的几列

索引不是建了就生效,关键看查询写法是否与索引结构“对得上”。多用 EXPLAIN 验证执行计划,比死记规则更可靠。不复杂但容易忽略。