从最左前缀到地址索引:我对 MySQL 索引的一次完整复盘

📅 2026/7/11 17:02:32
从最左前缀到地址索引:我对 MySQL 索引的一次完整复盘
一、缘起最左前缀原则一切从一个看似简单的问题开始索引的最左前缀原则只适用于联合索引吗答案是肯定的。最左前缀是联合索引Composite Index​ 的专属概念和 SQL 中WHERE条件的书写顺序无关只和索引定义时的字段顺序有关。css代码解读复制代码CREATE INDEX idx_a_b_c ON t(a, b, c);能走索引的查询ini代码解读复制代码WHERE a 1 WHERE a 1 AND b 2 WHERE a 1 AND b 2 AND c 3不能走索引的查询ini代码解读复制代码WHERE b 2 WHERE b 2 AND c 3更重要的是我纠正了自己一个误区SQL 里条件的左右顺序不重要索引定义里的左右顺序才重要。MySQL 优化器会自动重排条件WHERE b1 AND a1和WHERE a1 AND b1对优化器来说没有任何区别。二、EXPLAIN 的 type判断索引好坏的第一指标理解了最左前缀后自然引出了另一个问题我怎么知道索引到底用得好不好答案是看EXPLAIN的type字段。性能从好到坏sql代码解读复制代码const eq_ref ref range index ALLconst/eq_ref主键 / 唯一索引极致性能ref普通索引等值查询理想状态range索引范围扫描可接受index全索引扫描警惕ALL全表扫描必须优化慢查询优化的底线至少达到range。三、千万级数据下的索引实验为了验证这些理论我脑补了一个千万级订单表的场景并逐步推演。1️⃣ 联合索引 范围查询假设有 1000 万订单1000 个业务员索引如下scss代码解读复制代码CREATE INDEX idx_name_price ON orders(name, order_price);查询sql代码解读复制代码SELECT * FROM orders WHERE name IN (a, b) AND order_price 100;结论✅ 会走idx_name_price✅type range❌ 但SELECT *会导致大量回表2️⃣ 回表慢查询的隐形杀手回表指的是通过二级索引拿到主键 ID再回到聚簇索引取完整数据。回表本身不慢慢的是“大量随机回表”。于是我意识到一个经典优化手段延迟回表sql代码解读复制代码-- 第一步只拿 ID SELECT id FROM orders WHERE name IN (a,b) AND order_price 100; -- 第二步用 ID 查详情 SELECT * FROM orders WHERE id IN (...);✅ 第一次查询纯索引扫描无回表✅ 第二次查询主键精准定位顺序 IO回表慢不是因为“回”而是因为“乱回”。3️⃣ 范围查询 vs 等值查询继续推演如果把条件换成sql代码解读复制代码SELECT id, price FROM orders WHERE price 100;即使price上有索引且是覆盖索引Using index也可能并不快。原因是price 100可能命中30%50% 的数据扫描行数太多优化器甚至可能放弃索引选择全表扫描而如果换成等值查询ini代码解读复制代码SELECT id, price FROM orders WHERE price 100;情况完全不同type ref扫描行数极少即使数据完全无序BTree 也能毫秒级定位等值查询是索引的“王炸”范围查询才是需要警惕的。四、字符串索引地址查询的现实拷问最后我把问题推向了更复杂的现实场景如果给“地址”这种长文本建索引在千万级数据下等值查询还能瞬间返回吗答案是能但有代价。✅ 为什么能快BTree 不在乎数据类型字符串等值查询同样是 O(log N)查找复杂度与数字索引一致❌ 为什么工程上很少这么做索引体积大字符串比数字大 510 倍Buffer Pool 压力大写入成本高页分裂概率高写多场景性能下降数据不稳定地址输入不规范等值查询命中率低查询需求不匹配真实场景多为模糊查询LIKE %福田%✅ 更合理的做法拆字段province,city,district地址标准化 哈希索引复杂搜索交给 Elasticsearch不建地址索引不是因为慢而是因为“不值”。五、总结我对索引认知的四个层次通过这次复盘我对索引的理解从“会用”进化到了“懂权衡”语法层知道CREATE INDEX知道最左前缀诊断层会看EXPLAIN理解type/rows/Extra性能层明白回表、覆盖索引、等值 / 范围查询的差异工程层懂得索引的成本、数据分布的影响、业务场景的匹配一句话概括**索引解决的是“过滤”而不是“扫描”快不快不看有没有走索引而看扫了多少行。**附面试速记口诀最左前缀看定义不看 SQL 顺序type 至少到 range避免 ALL 和 index等值查询是王炸范围查询看比例回表怕多不怕有主键回表最稳妥字符串能快但不值地址拆分更合理这篇文章已经是一个完整的技术复盘了你发到博客上就是一份非常扎实的MySQL 索引学习笔记 面试素材。如果你愿意下一步我可以帮你✅ 给它起 35 个爆款标题适合掘金 / 知乎✅ 缩写成一个“面试 3 分钟自我介绍版”✅ 再补一篇番外《面试官问我那索引是不是建得越多越好》