建一张10万行的表,联合索引idx(a,b,c),用EXPLAIN对比只过滤b、只过滤a、过滤a+b、过滤a+b+c这四种情况,看最左匹配的生效方式。
建表 idx_abc(a,b,c),插入10万行,用4种不同的WHERE组合测EXPLAIN。
建表插入CREATE TABLE t2 (id INT PRIMARY KEY AUTO_INCREMENT, a INT, b INT, c INT, INDEX idx_abc(a,b,c)); 插入10万行:a=i%100, b=i%50, c=i%20
联合索引 idx_abc(a,b,c) 是按 a 排第一优先级、a相同再按b排、a和b都相同再按c排的一棵树——不是三个独立的索引拼在一起。
WHERE b=10,b不是联合索引的第一列。
EXPLAINEXPLAIN SELECT * FROM t2 WHERE b=10 → Filter: (t2.b = 10) (cost=10000 rows=10000) → Covering index scan on t2 using idx_abc (cost=10000 rows=100000)
的执行计划是"扫描整个 idx_abc 索引(10万行),再逐行过滤 b=10"——虽然扫的是索引不是表,但要把10万行全部过一遍,跟没走索引条件过滤差别不大。原因很直接:这棵树是先按a排序的,a取值杂乱分布时,符合b=10的记录会散落在整棵树的各个角落,索引没法帮你跳过任何一段连续区间。
测三种递增的过滤组合。
EXPLAIN结果WHERE a=10 → Covering index lookup on t2 using idx_abc (a = 10) (cost=101 rows=1000) WHERE a=10 AND b=10 → Covering index lookup on t2 using idx_abc (a = 10, b = 10) (cost=101 rows=1000) WHERE a=10 AND b=10 AND c=10 → Covering index lookup on t2 using idx_abc (a = 10, b = 10, c = 10) (cost=101 rows=1000)
只要WHERE条件从a开始(最左列),索引立刻就能用:"Covering index lookup"里括号中列出的条件,就是被索引利用到的部分。注意这里cost和rows估计值三次都一样(因为本文的数据分布下a本身已经把范围锁定到1000行,再加b、c并没有帮它缩小估计范围),但括号里能看到 (a = 10, b = 10, c = 10) 三个条件都被索引直接利用了,不需要事后再筛选。
每一步都是本文上面用EXPLAIN得到的原始结果。
EXPLAIN:对比不同过滤组合下的索引利用情况