穿透索引:从B+树的叶与枝到查询的覆盖与回表

一、索引

1.1、什么是索引?

MySQL中的索引是一种数据结构,它可以帮助数据库高效地查询、更新数据表中的数据。索引通过一定的规则排列数据表中的记录,使得对表的查询可以通过索引的搜索来加快速度

1.2、索引的作用

使用索引的根本目的是为了大幅减少数据库查询时需要扫描的数据量,从而将查询速度从"线性扫描"提升到"对数级甚至常数级查找",本质是用空间换时间。

二、索引的数据结构

2.1、Hash

使用哈希表查询速度非常快,时间复杂度为 0(1),但是哈希表不支持范围查找

2.2、二叉搜索树

二叉搜索树的中序遍历是一个有序数组,所以其支持范围查找,但是如下图。如果按序插入( 0050、0060、0080、0110、0999 )后,该二叉搜索树就退化成了一个单边树,时间复杂度为 O ( N ),在数据检索过程中,每次访问节点的子节点都会触发磁盘I/O操作。由于I/O操作是整个数据库系统的性能瓶颈,减少I/O次数能显著提升系统性能。

2.3、N叉树

N叉树每个节点可以有超过两个的子节点,能够解决树高问题,一般节点的个数小于度的个数

2.4、B+ 树

B+树经常用于数据库和文件系统等场合的平衡查找树,MySQL索引采用的就是 B+ 树,下图是4阶B+树

特点:

• 能够保持数据稳定有序,插入和修改操作的时间复杂度都一样,性能均衡

• 非叶子节点仅作为索引使用,不存储实际数据,所有真实数据均保存在叶子节点

• 所有叶子节点构成一个有序链表,可以按key排序的次序依次遍历全部数据记录

三、索引分类

3.1、主键索引

当在一个表上定义一个主键 PRIMARY KEY 时,会自动创建索引,索引的值为主键列的值,InnoDB 使用它作为聚集索引

复制代码
-- 方式一 创建表时创建主键
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20)
);
-- 方式二 单独指定主键列
CREATE TABLE aokey(
	id BIGINT auto_increment,
	name VARCHAR(20),
	PRIMARY KEY (id)
);
-- 方式三 修改表中的列为主键列
CREATE TABLE aokey(
	id BIGINT auto_increment,
	name VARCHAR(20)
);
ALTER TABLE aokey ADD PRIMARY KEY (id);

3.2、普通索引

最基本的索引类型,没有唯一性的限制(通常为查询频繁的列创建索引,但是会占用磁盘空间),可以为多列创建复合索引

复制代码
-- 方式一、创建表时创建唯一键
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20) UNIQUE
);
-- 方式二 单独指定唯一列
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20),
	UNIQUE (name)
);
-- 方式三 修改表中的列为唯一索引
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20)
);
ALTER TABLE aokey ADD UNIQUE (name);

3.3、唯一索引

当在一个表上定义一个唯一键UNQUE时,会自动创建唯一索引,有唯一性的限制

复制代码
-- 方式一、创建表时指定索引列
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20) UNIQUE,
	sno VARCHAR(10),
	INDEX(sno)
);
-- 方式二 修改表中的列为普通索引
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20),
	sno VARCHAR(10)
);
ALTER TABLE aokey ADD INDEX (sno);

-- 方式三 为表创建普通索引并指定索引名
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20),
	sno VARCHAR(10)
);
CREATE INDEX index_sno ON aokey(sno);

3.4、全文索引

主要用于文本内容搜索,基于文本列上创建

3.5、聚集索引

与主键索引同义,如果表中没有主键,InnoDB 使用第一个UNIQUE和NOT NULL 的类作为聚集索引

3.6、非聚集索引

聚集索引以外的索引称为非聚集索引或二级索引

四、使用索引

4.1、创建索引

在第三节索引分类我们已经演示了主键索引、普通索引和唯一索引的创建方式。此处我们补充复合索引的创建:

复制代码
-- 方式一、创建表时指定索引列
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20),
	sno VARCHAR(10),
	INDEX(name,sno)
);
-- 方式二 修改表中的列为复合索引
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20),
	sno VARCHAR(10)
);
ALTER TABLE aokey ADD INDEX (name,sno);

-- 方式三 为表创建复合索引并指定索引名
CREATE TABLE aokey(
	id BIGINT PRIMARY KEY auto_increment,
	name VARCHAR(20),
	sno VARCHAR(10)
);
CREATE INDEX index_name_sno ON aokey(name,sno);

4.2、查看索引

复制代码
SHOW KEYS FROM student;

SHOW INDEX FROM student;

4.3、删除索引

复制代码
ALTER TABLE student DROP PRIMARY KEY;

ALTER TABLE 表名 DROP INDEX 索引名;

4.4、索引覆盖

索引覆盖指查询语句所需的所有字段都包含在一个索引中,数据库引擎可以直接通过索引获取数据,无需回表查询主键或数据页

若我们仅查询 Id 和 name 的话,这两个字段的值包含在name列的普通索引树中的叶子节点中,就能直接从叶子节点查询到数据直接返回,该情况叫做索引覆盖

对于复合索引,是否走索引树取决于 "最左前缀原则",使用完整索引的话顺序无所谓~~

复制代码
CREATE TABLE aokey_demo (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT,
    city VARCHAR(50),
    INDEX idx_name_age_city (name, age, city)
);

-- 插入测试数据
INSERT INTO test_index VALUES
(1, 'aokey', 25, 'Beijing'),
(2, 'Bob', 30, 'Shanghai'),
(3, 'Alice', 28, 'Guangzhou');

-- 验证不同查询的索引使用
EXPLAIN SELECT * FROM aokey_demo WHERE name = 'aokey';
-- ✅ 使用索引(只用name)

EXPLAIN SELECT * FROM aokey_demo WHERE name = 'aokey' AND age = 25;
-- ✅ 使用索引(用name+age)

EXPLAIN SELECT * FROM aokey_demo WHERE name = 'aokey' AND age = 25 AND city = 'Beijing';
-- ✅ 完美使用完整索引

EXPLAIN SELECT * FROM aokey_demo WHERE age = 25;
-- ❌ 不使用索引(type: ALL,全表扫描)

EXPLAIN SELECT * FROM aokey_demo WHERE name = 'aokey' AND city = 'Beijing';
-- ⚠️ 使用索引,但只用name部分(age断层了)

4.5、回表查询

回表查询是指数据库通过非聚簇索引(二级索引)查找到主键值后,再根据主键值回到聚簇索引(主键索引)中查找完整数据行的过程

比如我们查询 Id 、name 和 sno 的话,name列的普通索引树中的叶子节点中只含有 name 和 Id ,没有 sno 的数据,就会返回 aokey 对应的主键值,再去主键索引树查询完整的数据并返回,这种情况叫做回表查询

相关推荐
小高不会迪斯科12 小时前
CMU 15445学习心得(二) 内存管理及数据移动--数据库系统如何玩转内存
数据库·oracle
e***89013 小时前
MySQL 8.0版本JDBC驱动Jar包
数据库·mysql·jar
l1t13 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
失忆爆表症14 小时前
03_数据库配置指南:PostgreSQL 17 + pgvector 向量存储
数据库·postgresql
AI_567814 小时前
Excel数据透视表提速:Power Query预处理百万数据
数据库·excel
SQL必知必会15 小时前
SQL 窗口帧:ROWS vs RANGE 深度解析
数据库·sql·性能优化
Gauss松鼠会16 小时前
【GaussDB】GaussDB数据库开发设计之JDBC高可用性
数据库·数据库开发·gaussdb
+VX:Fegn089516 小时前
计算机毕业设计|基于springboot + vue鲜花商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
识君啊16 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端
一个天蝎座 白勺 程序猿17 小时前
破译JSON密码:KingbaseES全场景JSON数据处理实战指南
数据库·sql·json·kingbasees·金仓数据库