别再乱用索引!日常开发最容易踩的 5 个索引误区 别再乱用索引日常开发最容易踩的 5 个索引误区“加了索引怎么还慢”“明明有索引为什么没走”“索引越多越好吗”如果你也在开发中经常发出这些灵魂拷问那大概率已经踩中了索引使用的常见误区。索引不是银弹用得好是“性能加速器”用不好就是“写入杀手 磁盘黑洞”。今天结合一线开发中最常见的真实案例聊聊5 个最容易踩的索引误区建议收藏写 SQL 前拿出来对照一下。误区一索引越多越好现象一个表十几个索引甚至几十个只要查询慢第一反应就是“再加个索引”问题本质索引并不是免费的。写性能下降INSERT / UPDATE / DELETE都要维护索引树索引越多写入越慢占用磁盘空间B 树索引很占地方尤其是大宽表 联合索引优化器选择困难索引太多MySQL 优化器可能选错索引反而更慢实战案例某订单表有 20 个索引包含多个重复前缀的联合索引INDEX idx_status_create(status, create_time) INDEX idx_status_pay(status, pay_time) INDEX idx_status_user(status, user_id)结果导致单条INSERT从 2ms 涨到 15ms高峰期写入大量锁等待正确做法控制单表索引数量一般建议不超过 5–7 个定期清理重复索引 / 冗余索引使用联合索引覆盖更多查询而不是为每个字段单独建索引✅ 一条好的联合索引往往能顶三五个单字段索引。误区二对低区分度字段建索引现象给gender、status、is_deleted这种字段单独建索引然后疑惑“为什么没走索引”问题本质索引的选择性Selectivity太低。以gender为例只有男 / 女 / 未知区分度极低优化器会认为“全表扫描比走索引回表成本更低”于是直接放弃索引。实战案例用户表 1000 万数据gender索引几乎从未被使用EXPLAIN SELECT * FROM user WHERE gender 男; -- type ALL全表扫描正确做法低区分度字段不要单独建索引更适合作为联合索引的后缀字段✅ 推荐写法-- 性别 创建时间 INDEX idx_gender_ctime (gender, create_time) -- 状态 业务时间 INDEX idx_status_ctime (status, create_time)这样既能过滤一部分数据又不影响索引效率。误区三索引列参与函数或运算现象查询条件里写函数、运算然后怀疑“我有索引啊怎么不走”问题本质索引列一旦参与表达式索引就失效除非使用函数索引。常见错误写法-- 对列使用函数 SELECT * FROM order WHERE DATE(create_time) 2024-01-01; -- 对列做运算 SELECT * FROM product WHERE price * 1.1 100; -- 隐式类型转换 SELECT * FROM user WHERE phone 13800138000; -- phone 是 VARCHAR实战案例某日志表create_time有索引但查询全表扫描EXPLAIN SELECT * FROM log WHERE DATE(create_time) CURDATE(); -- type ALL正确做法把运算留给常量保持索引列“干净”。✅ 改写后-- 时间范围查询 SELECT * FROM order WHERE create_time 2024-01-01 AND create_time 2024-01-02; -- 数值运算放右边 SELECT * FROM product WHERE price 100 / 1.1; -- 字符串严格匹配 SELECT * FROM user WHERE phone 13800138000; MySQL 8.0 可使用函数索引但能用普通索引就别折腾函数索引。误区四不懂最左前缀原则联合索引白建现象建了联合索引(a, b, c)查询只用了b、c然后说“索引没生效”问题本质联合索引本质是B 树的排序规则a → b → c必须从左到右连续使用才能发挥最大作用。查询条件是否走索引说明a ?✅走索引a ? AND b ?✅走索引a ? AND b ? AND c ?✅走索引b ?❌不满足最左前缀b ? AND c ?❌不满足最左前缀a ? AND c ?⚠️仅用到a实战案例索引(user_id, status, create_time)❌ 不走索引SELECT * FROM order WHERE status 1;✅ 走索引SELECT * FROM order WHERE user_id 1001 AND status 1;正确做法把高频等值查询字段放前面把范围查询字段放后面按实际 SQL 调整联合索引顺序而不是按直觉✅ 经典设计模板-- 用户 状态 时间范围 INDEX idx_user_status_ctime (user_id, status, create_time)误区五迷信EXPLAIN忽略真实数据分布现象只看EXPLAIN显示Using index上线后却发现依然慢问题本质EXPLAIN只是预估不是最终执行结果。常见问题统计信息过期ANALYZE TABLE很久没跑数据分布极度倾斜如某个 status 占了 90%回表成本极高大字段 大量行实战案例某表status 0的数据占比 95%优化器评估“扫 95% 的数据不如直接全表扫”即使EXPLAIN看起来“正常”执行依然慢。正确做法不要只看EXPLAIN要看实际执行时间和扫描行数定期执行ANALYZE TABLE your_table;关注关键指标rows扫描行数filtered过滤比例Extra中是否有Using temporary、Using filesort✅ 真正靠谱的判断标准响应时间 QPS CPU 消耗。Bonus一个快速自查清单 ✅下次写 SQL 或加索引前对照这 5 个问题这个索引真的有必要吗会不会和其他索引重复字段区分度高吗适合单独建索引吗索引列有没有参与函数、运算或隐式转换联合索引的顺序是否符合最左前缀原则除了EXPLAIN有没有验证真实执行效果写在最后索引优化的核心从来不是“多建索引”而是精准建索引。好的索引设计是对业务查询模式的理解差的索引设计是对数据库的慢性伤害。

本月热点