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

SQL查询出现全表扫描,通常是因为数据库优化器没走索引,转而逐行读取整张表——性能会随数据量增长急剧下降。核心问题不在于“有没有建索引”,而在于“查询条件能否有效触发索引的使用”。下面从常见场景出发,说清楚索引为啥失效、怎么避免。
WHERE条件中对索引列做了函数或运算
数据库无法直接用索引定位值,必须先计算每行结果再比对,索引自然被跳过。
-
❌ 失效写法:
WHERE YEAR(create_time) = 2023或WHERE price * 1.1 > 100 -
✅ 推荐写法: 改成范围查询,如
WHERE create_time >= '2023-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_id是VARCHAR,却写WHERE user_id = 123(数字);或status是TINYINT,却写WHERE status = '1' -
✅ 解决方法: 保持类型一致:字符串字段用引号,数值字段别加引号;用
EXPLAIN查看type是否为ALL,并检查Extra列是否含Using where; Using index
联合索引未遵循最左前缀原则
联合索引 (a, b, c) 实际上只对 a、(a,b)、(a,b,c) 三种组合高效;跳过左边列(比如只查 b 或 b,c),索引就用不上。
-
❌ 失效写法:
WHERE b = 2 AND c = 3(缺少a);WHERE a = 1 AND c = 3(跳过b) -
✅ 优化建议: 按查询高频模式设计联合索引顺序;必要时补充覆盖索引,如
(a,c)单独建;用EXPLAIN看key_len值,判断实际用了索引的几列
索引不是建了就生效,关键看查询写法是否与索引结构“对得上”。多用 EXPLAIN 验证执行计划,比死记规则更可靠。不复杂但容易忽略。










