covering-index
什么是索引覆盖?
- 一个查询所需的所有数据(包括 SELECT 列、WHERE 条件列、JOIN 列、ORDER BY 列等)都可以直接从索引树中获取,而无需回表。
所谓回表,查询过程中通过索引的B+树查询,但是叶子节点中没有存储非索引列的值,于是根据主键ID,到聚簇索引查询整行数据,再获取具体列的值。(也就是查询过程即使走了索引,但是仍然再根据主键ID再查一次)
在 MySQL 的 InnoDB 引擎中,数据存储结构分为两种:
- 聚簇索引(Clustered Index):通常是主键索引,叶子节点存储的是整行数据。
- 二级索引(Secondary Index / 非聚簇索引):叶子节点存储的是索引列的值 + 主键值。
索引覆盖就是为了解决回表现象的解决方案。
如果查询的列全部都包含在某个二级索引中,那么 MySQL 直接从这个二级索引里就能拿到所有需要的数据,完全不需要去查聚簇索引。
比如 users 表,建立联合索引 idx_name_age (name, age)
SELECT name, age FROM users WHERE name = 'Alice';
理解索引覆盖的前提是:认识InnoDB存储引擎的两种索引结构——聚簇索引(Clustered Index) & 二级索引(Secondary Index)
聚簇索引叶子节点存储的是 主键值 & row(record的完整记录),因此
where id = 1这样的查询直接就能获取该行的每个字段值,也就不存在回表的说法。
二级索引叶子节点存储的是二级索引列值 & 主键值,因此select col(非索引列) from t where index_col = xxx;这样的查询必须回表,经由聚簇索引再查询一次。
B+Tree (Clustered Index)
非叶子节点
↓
[ key | pointer ]
叶子节点
↓
[ 主键值 | col1 | col2 | col3 | ... | colN ]
二级索引 B+Tree
非叶子节点
↓
[ key | pointer ]
叶子节点
↓
[ 二级索引列值 | 主键值 ]