数据库索引失效:写了索引,却没走索引的几种情况
给表加了索引,查询还是慢,执行计划里显示全表扫描。这种情况很常见:索引建了,不等于查询会用它。索引失效的原因大多出在写法上,改写法比加索引更管用。
对索引列做运算或函数处理
这是最常见的失效原因。查询条件里对索引列用了函数或表达式,比如对日期字段用 DATE_FORMAT、对字符串用 SUBSTR、或者做加减乘除,数据库就没法直接用索引定位,只能把每一行都算一遍再比较。
正确的做法是把运算挪到另一边。想查某一天的数据,不要对日期列做函数转换,而是用范围条件:大于等于当天的零点、小于第二天的零点。条件里索引列保持“干净”,只出现列名本身,数据库才能走索引。
隐式类型转换
索引列是字符串类型,查询时传了数字,或者反过来,数据库会偷偷做类型转换,转换之后索引就失效了。典型的例子是手机号字段是 VARCHAR,查询时写成 WHERE phone = 13800000000(没加引号),数据库把每一行的 phone 转成数字再比较,全表扫描就来了。
避免的办法很简单:查询条件里值的类型和列定义保持一致。字符串列就用字符串字面量,数字列就用数字。类型不一致时别指望数据库帮你兜底,它兜底的方式就是放弃索引。
用了 OR,但不是所有分支都有索引
WHERE 条件里用 OR 连接多个条件,只要其中一个分支没有可用的索引,整个查询就可能退化成全表扫描。数据库要保证结果完整,不能只走一部分索引再拼另一部分的全表扫描,干脆全表扫一遍更省事。
如果 OR 的每个分支都有索引,数据库可以用索引合并;如果做不到,就把 OR 拆成 UNION:每个分支单独走自己的索引,最后合并去重。拆开写比硬拼一个 OR 更容易让优化器选对路。
LIKE 以通配符开头
LIKE 'abc%' 可以走索引,因为前缀是确定的,数据库能定位到范围。但 LIKE '%abc' 以通配符开头,前缀不确定,索引帮不上忙,只能逐行匹配。百分号在前面,索引就失效;在后面,索引还能用。
如果业务上确实需要模糊匹配,可以考虑全文索引,或者把查询改成前缀匹配加应用层过滤。不要在数据量大的表上对高频查询用前置通配符,那是全表扫描的稳定来源。
范围条件后面的列用不上
复合索引讲究最左前缀。索引是 (a, b, c),查询条件是 a = 1 AND b > 5 AND c = 10,c 这个条件是用不上索引的:b 是范围条件,范围后面的列在索引里的顺序就乱了,数据库只能在 b 的范围里再逐行过滤 c。
调整的思路是把等值条件往前放、范围条件往后放。索引设计时就应该把选择性高、经常做等值查询的列放在前面,范围查询的列放在后面。顺序错了,复合索引有一半是白建的。
结尾:先看执行计划,再动索引
遇到慢查询,第一步不是加索引,而是看执行计划。执行计划会告诉你这条查询到底走了哪个索引、扫描了多少行、过滤条件发生在哪一步。很多时候问题不在索引缺失,而在写法让已有索引失效。
索引是工具,不是越多越好。每多一个索引,写入就要多维护一份结构,查询优化器要选择的时间也变长。先把写法改对,让已有的索引真正被用上,再考虑是不是缺索引。
- 点赞
- 收藏
- 关注作者
评论(0)