索引未被使用主因是查询条件未触发“可下推”路径:如like '%张'、函数操作year(create_time)等;需用explain检查type为all或key为null,并避免隐式转换、确保最左前缀匹配。

为什么加了索引还是全表扫描
索引没被用上,不是因为建得不对,而是查询条件没触发索引的“可下推”路径。比如 WHERE name LIKE '%张',左侧通配符直接让 B+ 树失效;又或者对字段做了函数操作,像 WHERE YEAR(create_time) = 2023,MySQL 无法用 create_time 上的索引。
- 检查执行计划:务必用
EXPLAIN看type是否为ALL,再看key列是否为NULL - 避免在索引列上使用函数、表达式或隐式类型转换(比如字符串字段和数字比较)
- LIKE 查询尽量以常量开头:
LIKE '张%'可走索引,LIKE '%张%'不行(除非用全文索引) - 联合索引要注意最左前缀:查询只用后缀列(如索引是
(a,b,c),却只查WHERE c = 1)不会命中
哪些字段值得建索引
不是所有高频 WHERE 字段都该加索引。索引有维护成本,写多读少的字段反而拖慢 INSERT/UPDATE;低区分度字段(比如性别、状态位)建了也大概率不走。
- 优先建在
WHERE、JOIN ON、ORDER BY、GROUP BY中出现的字段 - 高选择性字段更有效:用
SELECT COUNT(DISTINCT col)/COUNT(*) FROM table粗略估算,结果越接近 1 越适合 - 小字段优于大字段:
VARCHAR(10)比TEXT更适合作索引列;长字符串考虑前缀索引(但需验证前缀长度是否够区分) - 避免冗余索引:已有
(a,b)就别单独建(a),MySQL 8.0+ 会警告
ORDER BY 和 LIMIT 配合索引失效的典型场景
很多人以为加了 LIMIT 10 就能跳过排序开销,其实如果 ORDER BY 字段没索引,MySQL 仍要先排序全部结果再截断——全表扫描 + 文件排序(Using filesort)双杀。
-
ORDER BY必须和索引顺序严格一致(包括 ASC/DESC),且不能混用方向(如INDEX(a ASC, b DESC),却查ORDER BY a ASC, b ASC) - 如果
WHERE和ORDER BY涉及不同字段,联合索引要把WHERE列放前面,ORDER BY列紧随其后 -
LIMIT本身不减少扫描行数,只是限制返回;真正减少扫描的是覆盖索引 + 合理的WHERE条件 - 用
EXPLAIN观察Extra列:出现Using index condition是好信号,Using filesort或Using temporary就得优化
覆盖索引怎么写才真省 IO
覆盖索引不是“建个索引就行”,而是让查询所有需要的列都在索引 B+ 树叶子节点里,彻底避免回表。否则即使走了索引,还要根据主键再去聚簇索引捞数据,IO 翻倍。
- 把
SELECT列全部包含进索引:比如查SELECT id, name, email FROM user WHERE status = 1,索引应建为(status, id, name, email) - 注意顺序:
WHERE条件列必须在前,之后才是SELECT列;否则无法保证覆盖 - 别盲目加太多列:索引变宽会降低缓存效率,尤其对写频繁的表,权衡字段数量和查询频次
- 用
EXPLAIN看Extra是否出现Using index(注意不是Using index condition)
最常被忽略的一点:复合条件下的索引合并(index_merge)看起来用了两个索引,实际性能往往不如一个设计合理的联合索引——它要分别扫描再取交集/并集,CPU 和内存开销更大。别迷信“多个单列索引能自动组合”。










