
一、索引
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 对应的主键值,再去主键索引树查询完整的数据并返回,这种情况叫做回表查询
