MySQL 索引失效的六种常见写法

米阳 2022-1-8 6 1/8

建了索引却还在全表扫描,是日常开发里最常见的困惑。这篇把线上真实遇到过的几种情况整理一下,都不是玄学,都有明确原因。

一、列上套了函数或运算

-- 走不了索引
SELECT * FROM orders WHERE DATE(created_at) = '2021-12-01';
-- 改成范围查询
SELECT * FROM orders WHERE created_at >= '2021-12-01' AND created_at < '2021-12-02';

索引里存的是 created_at 的原始值,一旦被函数包住,B+ 树就没法按顺序定位。同理 WHERE id + 1 = 100 也失效。

二、隐式类型转换

用户表 phone 是 varchar,查询写成 WHERE phone = 13800000000(不带引号)。MySQL 会把字符串列逐行转成数字再比较,索引直接废掉。这类问题在接口参数没做类型校验时特别容易发生。

三、前导通配符

LIKE '%关键词' 无法使用索引的有序性,LIKE '关键词%' 可以。真要做全文模糊匹配,应该上全文索引或搜索引擎,别硬扛。

四、OR 连接了未建索引的列

SELECT * FROM article WHERE title = 'abc' OR remark LIKE '%abc%';

只要 OR 两边有一个走不了索引,整体就退化为全表扫描。拆成两条 SQL 用 UNION ALL 合并,往往比强行优化更快。

五、违背最左前缀

联合索引 (a, b, c),查询条件只有 b = 1,用不上。条件里出现 a > 1 AND b = 2 时,b 也用不上——范围查询之后的列失去有序性。

六、统计信息过期

大批量导入或删除之后,优化器对数据分布的估计会失准,可能错判成“全表扫描更便宜”。ANALYZE TABLE 表名; 刷新统计信息,多数情况立刻恢复。

怎么确认

不要凭感觉,直接看执行计划:

EXPLAIN SELECT ...;

重点关注 type 是否到了 range/ref,key 有没有命中,rows 估算行数是否接近全表,Extra 里出现 Using filesort、Using temporary 也要留意。

结论很简单:索引失效几乎都能从“列被加工过”“顺序被打断”“类型不一致”这三条里找到答案。

- THE END -

米阳

1月08日10:20

最后修改:2022年1月8日
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论