建了索引却还在全表扫描,是日常开发里最常见的困惑。这篇把线上真实遇到过的几种情况整理一下,都不是玄学,都有明确原因。
一、列上套了函数或运算
-- 走不了索引
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 也要留意。
结论很简单:索引失效几乎都能从“列被加工过”“顺序被打断”“类型不一致”这三条里找到答案。
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://mi-blog.cn/archives/650
共有 0 条评论