起本机MySQL 26.7单节点,用EXPLAIN FORMAT=TREE验证二级索引的叶子节点里到底存了什么——为什么查主键列不用回表,查其它列却要多访问一棵树。
建一张表,主键id,普通列k上建二级索引,插入10万行。
建表插入CREATE TABLE t1 (id INT PRIMARY KEY, k INT, v VARCHAR(50), INDEX idx_k(k)); 插入10万行,k = id % 1000(每个k值对应100行)
这张表有两棵 B+树:一棵是聚簇索引(按 id 排序,叶子节点直接存整行数据),一棵是二级索引 idx_k(按 k 排序,叶子节点存的是什么,这篇验证)。
用 EXPLAIN FORMAT=TREE 分别查id、k、v这三列,看有没有触发"回表"。
结果EXPLAIN FORMAT=TREE SELECT id FROM t1 WHERE k=500 → Covering index lookup on t1 using idx_k (k = 500) (cost=10.3) EXPLAIN FORMAT=TREE SELECT k FROM t1 WHERE k=500 → Covering index lookup on t1 using idx_k (k = 500) (cost=10.3) EXPLAIN FORMAT=TREE SELECT v FROM t1 WHERE k=500 → Index lookup on t1 using idx_k (k = 500) (cost=35)
结果很直接:查 id(主键本身)和查 k(索引列本身)都显示 "Covering index lookup"——不用碰聚簇索引这棵树。只有查 v(既不是主键也不是索引列)才变成普通的 "Index lookup",cost 也从10.3涨到35。
当二级索引里没有你要的列,InnoDB 要做什么。
过程是:先在 idx_k 这棵树里用 k=500 做的范围/等值查找,找到符合条件的记录,每条记录里带着对应的主键值 id;然后拿这个 id,去聚簇索引那棵树里再做一次查找,取出这一行的完整数据(包括 v)。这两次的树查找,加起来才是一次"回表"查询的代价——这也是为什么 EXPLAIN 里能看到 cost 从 10.3 涨到 35,多出来的部分就是第二棵树查找的代价。
每一步都是本文上面用EXPLAIN FORMAT=TREE得到的原始结果。
EXPLAIN FORMAT=TREE:区分Covering index lookup与Index lookup