ARTICLE DETAIL

资讯详情

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

MySQL索引失效的八个场景,面试答对六个就算过关

MySQL索引失效的八个场景,面试答对六个就算过关 “明明建了索引为什么查询还是慢”——这个问题在面试中被问到的频率几乎和“说一下HashMap的原理”一样高。很多开发者能背出几条索引失效的场景但被追问“为什么失效”时就卡住了。索引失效的根本原因其实只有两条线结构性失效——查询条件无法利用B树的有序结构成本性失效——优化器算了一笔账觉得走索引比全表扫描还慢。把下面八个场景吃透面试时答对六个就算过关。场景一违反最左前缀原则这是联合索引最常见的坑。假设有一个联合索引(a, b, c)B树先按a排序a相同再按b排序b相同再按c排序。查询WHERE b 1 AND c 2跳过了最左列a索引无法定位。记住查询条件必须从索引的最左列开始连续使用跳过任何一列后面的索引全部作废。场景二在索引列上使用函数或表达式索引存储的是列的原始值你写WHERE DATE(create_time) 2023-01-01相当于拿“加工后的值”去查原始值的索引树树根本帮不上忙。解决方案很简单把函数从列上挪走改成范围查询——WHERE create_time 2023-01-01 AND create_time 2023-01-02。场景三隐式类型转换字段是VARCHAR类型你传了个数字进去WHERE phone 13800001111。MySQL发现类型不匹配会悄悄把phone这一列的值挨个转换成数字再比较——逐行转换意味着逐行扫描索引直接失效。解决方案保持类型一致传字符串就用引号括起来。场景四LIKE以通配符开头LIKE %abc或LIKE %abc%MySQL不知道开头是什么无法利用B树的有序性进行前缀匹配。而LIKE abc%是可以走索引的因为开头确定可以利用树的二分查找。场景五OR连接了非索引字段WHERE name Alice OR age 30假设name有索引但age没有。MySQL无法通过一个索引同时满足两个条件。解决方案用UNION拆分查询或者确保OR两边的字段都有索引。场景六范围查询右侧的列失效联合索引(a, b, c)查询WHERE a 10 AND b 1。a走了范围索引但a的范围查询导致B树中b字段在大于10的那部分是无序的。因此范围条件右边的所有列都无法使用索引。最佳实践把范围查询的字段放在联合索引的最右边。场景七使用!、或NOT IN不等于操作符匹配的数据范围通常很大超过全表20%-30%时优化器认为回表成本太高不如全表扫描。如果确实需要排除少量数据可以尝试用IN列举或用UNION改写。场景八优化器因成本估算放弃索引这是最容易忽略的场景——索引本身没问题但优化器觉得走索引不划算。三种典型情况表太小几条数据全表扫描更快索引选择性太低比如性别字段区分度极差统计信息过期导致优化器误判。解决方案对低选择性字段慎建索引定期执行ANALYZE TABLE更新统计信息。如何排查索引是否失效用EXPLAIN看执行计划。重点关注三列typeALL表示全表扫描要警惕、keyNULL表示没用到索引、rows扫描行数越少越好。以上八个场景面试时能说出六七个并解释清楚原理面试官基本会给过。但更重要的是在日常开发中养成良好的SQL习惯——写查询时多想一步“这个条件能不能利用索引的有序结构”才是避免踩坑的根本之道。
返回列表