ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MySQL 索引失效的六个真实场景:建了索引为什么还是慢

MySQL 索引失效的六个真实场景:建了索引为什么还是慢 个人主页 我不会起名字322 欢迎各位大佬莅临其他栏目 技术栈学习笔记 其他栏目 力扣Hot100题目解析 其他栏目 Go项目学习笔记 文章目录MySQL 索引失效的六个真实场景建了索引为什么还是慢先说结论第一步先确认它到底用没用场景一在索引列上做运算或套函数场景二隐式类型转换场景三最左前缀断裂场景四LIKE 以 % 开头场景五OR 连接了没有索引的列场景六范围查询截断了后面的列两个能白捡性能的机制一张排查清单MySQL 索引失效的六个真实场景建了索引为什么还是慢先说结论线上慢查询里真正缺索引的比例比想象中低。更常见的是索引建了但优化器用不上——你去SHOW INDEX看索引明明在那儿。这篇不讲 B 树原理只讲怎么把没生效的索引找出来、以及它为什么不生效。第一步先确认它到底用没用别猜看执行计划EXPLAINSELECT*FROMordersWHEREuser_id10086ANDstatus1;重点看四列列看什么type出现ALL就是全表扫index是全索引扫都不好至少要range最好是ref/eq_refkey实际用了哪个索引。是NULL就说明一个都没用上rows预估扫描行数。这个数接近表总行数索引基本等于白建ExtraUsing filesort、Using temporary都是要警惕的信号一个反直觉的点possible_keys有值但key是NULL说明优化器评估后主动放弃了你的索引。这时候不要急着加FORCE INDEX先想清楚它为什么放弃——通常是下面六种情况之一。场景一在索引列上做运算或套函数-- 用不上 idx_created_atSELECT*FROMordersWHEREDATE(created_at)2026-03-01;-- 改成范围查询就能用上SELECT*FROMordersWHEREcreated_at2026-03-01 00:00:00ANDcreated_at2026-03-02 00:00:00;索引里存的是created_at的原值不是DATE(created_at)的值。你对列做了变换B 树就没法按序定位了。要变的是条件右边的常量不是左边的列。场景二隐式类型转换-- phone 是 varchar这里传了数字SELECT*FROMusersWHEREphone13800138000;MySQL 会把varchar列转成数字来比较等价于给列套了函数索引直接失效。而且这个坑特别隐蔽——SQL 写得看起来没问题参数是框架传进来的你不看表结构根本发现不了。统一约定字符串字段的参数一律用字符串。场景三最左前缀断裂联合索引idx_a_b_c (a, b, c)WHEREa1ANDb2ANDc3-- ✅ 全用上WHEREa1ANDc3-- ⚠️ 只用到 ac 用不上WHEREb2ANDc3-- ❌ 完全用不上记住一点联合索引是按 (a, b, c) 的顺序一层层排下去的。跳过a直接找b就像查字典不知道拼音却想直接翻到某一页。所以复合索引的字段顺序要按实际查询里出现频率和区分度来定不是按表结构顺序。场景四LIKE 以 % 开头WHEREnameLIKE张%-- ✅ 能用WHEREnameLIKE%张%-- ❌ 用不上前缀不确定就没法在 B 树里定位。如果确实要做全文模糊匹配考虑全文索引或者上 ES别硬扛。场景五OR 连接了没有索引的列WHEREa1ORd2-- d 无索引 → 整体退化成全表扫只要 OR 两边有一个走不了索引整体就走不了。改写成UNION ALL往往能救回来SELECT...WHEREa1UNIONALLSELECT...WHEREd2ANDa1;场景六范围查询截断了后面的列-- idx_a_b_c (a, b, c)WHEREa1ANDb10ANDc3b用了范围查询之后c就没法再用于精确定位了只能靠索引下推在存储引擎层过滤减少回表但定位不到。所以设计复合索引时把等值条件放前面、范围条件放最后。两个能白捡性能的机制覆盖索引查询需要的列全在索引里就不用回表。-- 如果存在 idx_user_status (user_id, status)SELECTuser_id,statusFROMordersWHEREuser_id10086;-- Extra 会显示 Using index这是最理想的状态索引下推ICPMySQL 5.6把 WHERE 里能靠索引判断的条件下推到存储引擎层减少回表次数。Extra里显示Using index condition就是它生效了。一张排查清单现象大概率原因key是NULLpossible_keys有值列上套了函数 / 隐式类型转换 / 最左前缀断裂type是ALL没建索引或 OR 里有非索引列rows远大于预期区分度太低如性别字段索引没意义Extra有Using filesort排序字段没进索引或顺序与索引不一致索引都在但就是慢回表太多考虑覆盖索引最后一句提醒索引不是越多越好。每个索引都会拖慢写入而且优化器要在多个索引之间做选择索引太多反而可能选错。定期用sys.schema_unused_indexes看看哪些索引从来没被用过该删就删。
返回列表