当前位置: 首页 > news >正文

[MySQL] 页与索引

MySQL 索引是提升查询效率的核心机制 , 基于特定的数据结构(B+树,哈希等)对数据进行预排序和快速定位 , 避免全表扫描

一.索引使用哪种数据结构

1.哈希索引

  • 基于哈希表 , 键值直接映射到存储位置 , 查询的时间复杂度为 O(1)
  • 适合精度匹配(=) , 但不支持范围查询 , 排序 , 模糊查询

2.B+树索引(最常用)

2.1 B+树简介

B+树是一种经常用于数据库和文件系统等场合的平均查找树 , MySQL 索引采用的数据结构 , 以 4 阶 B+树为例

在二叉搜索树的基础上可以有效控制树高 , 也就意味着在在相同数据量的情况下 可以有效减少 IO 次数 , 从而提升效率

2.2 B+ 树特点

  • 能够有效保持数据稳定有序 , 插入与修改有较稳定的时间复杂度
  • 非叶子结点仅具有索引的功能 , 不存储数据 , 所有叶子结点保存真实数据
  • 所有叶子结点构成一个有序链表 , 可以按照 Key 排序的次序来依次遍历全部数据

2.3 B+树与 B 树的对比

  1. 叶子结点之间有一个相互连接的引用 , 使数据连续去 , 且相互链接 , 便于区间查找和搜索 , 并且在 MySQL中使用的是双向链表
  2. 非叶子结点的值都包含在叶子节点中 , MySQL 非叶子结点之保存了对叶子结点的引用 , 没有保存真实数据 , 所有的真实数据都保存在叶子结点中
  3. 对于 B+树而言 , 在相同树高的情况下 , 查找任意元素的时间复杂度都是一样的 , 性能均衡

2.4 B+树索引的使用

  • 所有数据都保存在叶子结点中 , 非叶子结点仅保存索引键 , 形成有序链表 , 支持范围查找
  • 适用于范围查找(>,<,BETWEEN) , 排序(ORDER BY) , 多列联合查询

2.5 B+树在 MySQL 索引中的应用

非叶子结点保存索引数据 , 叶子结点保存真实数据

二 . 索引中的页

1.索引与页的关系

MySQL 索引(B+树)的每一层结点都是独立的页 , 通过页内指针和页间链表组织 , 实现高效数据查询

# B+ 树索引与页的对应关系
┌─────────────────────────────────────────────────────┐
│  根节点页(16KB) - 非叶子节点                      │
│  ┌───────────┬───────────┬───────────┬───────────┐  │
│  │ 键值:100  │ 键值:200  │ 键值:300  │ 键值:400  │  │
│  │ 指针:页2  │ 指针:页3  │ 指针:页4  │ 指针:页5  │  │
│  └───────────┴───────────┴───────────┴───────────┘  │
└─────────────────────────────────────────────────────┘↓           ↓           ↓           ↓
┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 子节点页2     │ │ 子节点页3     │ │ 子节点页4     │ │ 子节点页5     │
│ (非叶子节点) │ │ (非叶子节点) │ │ (非叶子节点) │ │ (非叶子节点) │
└───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘↓           ↓           ↓           ↓
┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 叶子节点页10  │ │ 叶子节点页11  │ │ 叶子节点页12  │ │ 叶子节点页13  │
│ (聚簇索引:  │ │ (聚簇索引:  │ │ (聚簇索引:  │ │ (聚簇索引:  │
│  存储完整数据) │ │  存储完整数据) │ │  存储完整数据) │ │  存储完整数据) │
│  ┌─────────┐  │ │  ┌─────────┐  │ │  ┌─────────┐  │ │  ┌─────────┐  │
│  │ id:1-99 │  │ │  │id:100-199│  │ │  │id:200-299│  │ │  │id:300-399│  │
│  └─────────┘  │ │  └─────────┘  │ │  └─────────┘  │ │  └─────────┘  │
│  前指针:null  │ │  前指针:页10  │ │  前指针:页11  │ │  前指针:页12  │
│  后指针:页11  │ │  后指针:页12  │ │  后指针:页13  │ │  后指针:null  │
└───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘

2.为什么使用页 ?

在.ibj 文件中最重要的结构体就是页 , 页是内存与磁盘交互的最小单元 , 默认大小是 16 KB , 每次内存与磁盘交互至少读一页 , 所以在磁盘中每个页内部的地址都是连续的 , 之所 以这样做,是因为在使⽤数据的过程中,根据局部性原理,将来要使⽤的数据⼤概率与当前访问的 数据在空间上是临近的,所以⼀次从磁盘中读取⼀⻚的数据放⼊内存中,当下次查询的数据还在这 个⻚中时就可以从内存中直接读取,从⽽减少磁盘I/O提⾼性能

局部性原理: 是指程序在执⾏时呈现出局部性规律,在⼀段时间内,整个程序的执⾏仅限于程序中的某⼀部 分。相应地,执⾏所访问的存储空间也局限于某个内存区域,局部性通常有两种形式:时间局部 性和空间局部性。

时间局部性(TemporalLocality):如果⼀个信息项正在被访问,那么在近期它很可能还会被再 次访问。

空间局部性(SpatialLocality):将来要⽤到的信息⼤概率与正在使⽤的信息在空间地址上是临 近的

  • 每个页即使没有数据也会使用 16KB 空间 , 同时与索引的 B+树种的结点对应

3 索引结点与页之间的关系

  • 每个 B+ 树结点都是一个独立的 16KB 页
  • 非叶子结点页 : 仅存储 索引键值 和 子节点页的指针
  • 叶子节点 : 聚簇索引种存储完整数据记录 , 二级索引中存储键值和主键值

4 数据页的基本结构

① 文件头部 file header(38 字节)

  • 存储页的元数据 , 用于标识页的基本信息和关联关系
  • 核心字段:

page number : 页的唯一编号 , 用于定位页在磁盘上的位置

prev page / next page : 上一页/下一页的编号 , 形成双向链表(方便范围查询)

page typr : 页的类型(索引页 , 数据页 , undo 日志页)

checksum : 页的校验和 , 用于验证数据的完整性

② 数据页头 page header(56 字节)

  • 存储页的状态信息 , 描述页内部数据的组织情况
  • 核心字段 :

page level : 当前页在 B+ 树种的层级

record count : 页内存储的用户记录数

free space offset : 空闲空间的起始偏移量(标识空闲空间的位置)

directory slot count : page directory 中的槽数量 (用于快速定位记录)

③infimum + supremum(最小/最大记录 , 固定存在)

  • 两个虚拟的记录 , 不存储实际数据 , 用于定义页内记录的边界

④User Records(用户记录)

  • 存储实际的表数据或索引键值(聚簇索引页存完整数据,二级索引页存键值 + 主键)。
  • 记录按 “行格式” 存储(如 Compact、Dynamic 格式),包含字段值、隐藏列(如主键 ID、事务 ID、回滚指针)。

⑤Free Space(空闲空间)

  • 页内未使用的连续空间,呈动态变化。
    插入记录时,从空闲空间分配内存;删除记录时,释放的空间会合并到空闲空间。
  • 当空闲空间不足时,会触发页分裂(Page Split)。

⑥Page Directory(页面目录)

  • 类似 “书籍目录”,用于快速定位页内记录,避免全页扫描。
    存储部分记录的偏移量(按主键排序),每个偏移量称为一个 “槽”(Slot)。
  • 查找记录时,先通过二分法定位槽,再在槽对应的记录区间内遍历查找。

⑦File Trailer(文件尾部,8 字节)

  • 用于校验页的完整性,确保页在磁盘 I/O 过程中未损坏。
  • 核心字段

Checksum:与 File Header 中的校验和一致,用于比对验证。
LSN(Log Sequence Number):页的日志序列号,关联事务日志,确保数据持久化

5. 三层 B + 树的存储容量计算

三层 B + 树结构为 “根节点索引页 → 二级节点索引页 → 叶子节点数据页”因此总记录数为:根节点索引记录数 × 二级节点索引记录数 × 叶子节点数据记录数 = 1170 × 1170 × 16 = 21,902,400

三层树高的 B + 树可存储约 2190 万条记录,且检索时只需三次 I/O(对应树的三层访问),体现了 B + 树在大规模数据存储与高效检索上的优势

三 . 索引的分类

1.按功能与约束划分

① 主键索引 ( PRIMARY KEY)

  • 当在一个表中定义一个主键时 , 自动创建 , 唯一且非空 , 一个表只能有一个主键索引 , 索引值是主键的值 , InnoDB 中使用它为聚簇索引

② 普通索引 (INDEX)

  • 无任何约束 , 仅用于加速查询 , 允许列值重复 , 是最基础的索引类型
  • 可能为多列创建组合索引,称为复合索引或组全索引

③ 唯一索引 (UNIQUE)

  • 当在一个表上定义一个唯一键时 , 自动创建唯一索引
  • 与普通索类似 , 区别是 唯一索引的列不允许有重复值

④ 联合索引(多列索引)

  • 由多个列组合创建的索引 , 遵循'最左前缀匹配原则' : 查询序包含最左列才能命中索引
  • 适用于多条件查询 , 需要合理安排排列顺序(区分高度的列放在左侧)

⑤ 全文索引(按数据结构划分)

  • 基于文本列(CHAR , VARCHAR 或 TEXT)上创建 , 以加快对这些类中包含的数据查询和 DML 操作
  • 用于全文搜索 , 仅 MYSQAM 和 InnoDB 引擎支持

2.按存储方式划分 (InnoDB 引擎)

① 聚簇索引(clustered index)

  • 主键索引默认时聚簇索引 , 如果没有为表定义主键 , InnDB 使用第一个 唯一键和非空列作为聚集索引
  • 如果表中没有主键或合适的唯一键索引 , InnoDB 会为新插入的行生成一个行号并用 6 字节 的 row_id 字段记录 , row_id 单调递增 , 并使用 row_id 作为索引(隐藏列)

索引与数据存储在一起 , 叶子结点即数据记录 , 仅主键索引是聚簇 索引

优势 查询主键时无需徽标 , 效率高 ; 劣势 主键更新会导致数据移动 , 影响性能

② 二级索引(secondary index)

  • 聚集索引以外的索引称为 非聚集索引或而二级索引
  • 二级索引中的每条记录都包含该行的主键列 , 以及二级索引指定的列
  • InnoDB 使用这个主键值来搜索聚集索引中的行 , 这个过程称为回表查询

③ 索引覆盖

  • 查询字段均在索引中无需回表的优化方式

四.使用索引

1.查看索引

① 方式 1 : show keys from 表名

② 方式 2 : show index from 表名

③ 方式 3 : 简要信息 : desc 表名

查看索引信息

2.自动创建

  • 当我们为一张表加主键约束 , 外键约束 , 唯一约束时 , MySQL 回为对应的列自动创建一个索引
  • 如果表不指定任何约束时 , MySQL 会自动为每一列生成一个索引并用 ROW_ID 进行标识

3.手动创建

① 主键索引

  • 方式 1 : 创建表时创建主键
create table t_test_pk(id bigint primary key auto_increment,name varchar(20)
);

  • 方式 2 : 创建表时单独指定主键列
create table t_test_pk1(id bigint auto_increment,name varchar(20),primary key(id)
);

  • 方式 3 : 修改表中的列为主键索引

语法 : alter table 表名 [add | modify | drop] 要修改的内容

示例 : alter table t_test_pk2 modify id bigint auto_increment;

create table t_test_pk2(id bigint,name varchar(20)
);
alter table t_test_pk2 add primary key(id);#为表中添加主键 , 并指定ID

② 唯一索引

  • 方式 1 : 创建表时创建唯一键
create table t_test_uk(id bigint primary key auto_increment,name varchar(20) unique
);

  • 方式 2 : 创建表时单独指定唯一列
create table t_test_uk1(id bigint primary key auto_increment,name varchar(20),unique (name)
);

  • 方式 3 : 修改表中的列为唯一索引
create table t_test_uk2(id bigint primary key auto_increment,name varchar(20)
);
alter table t_test_uk2 add unique (name);

4.普通索引

按创建的时机分为两种

① 创建表时指定索引列

create table t_test_index(id bigint primary key auto_increment,name varchar(20) unique,sno varchar(10),index(sno)
);

② 修改表中的列为普通索引

create table t_test_index1(id bigint primary key auto_increment,name varchar(20),sno varchar(10)
);
alter table t_test_index1 add index(sno);

③ 单独创建索引并指定索引名

语法 : create index 索引名(一般为 index_ 表名 _ 列名) on 表名(列名);

create table t_test_index2(id bigint primary key auto_increment,name varchar(20),sno varchar(10) 
);
create index index_name on t_test_index2(sno);

5.创建复合索引

创建语法与创建普通索引相同 , 只不过指定多个列 , 列与列之间用逗号隔开

① 创建表时指定索引列

create table t_test_index4(id bigint primary key auto_increment,name varchar(20),sno varchar(10),class_id bigint,index(sno,class_id) # 复合主键
);

此时索引名默认是第一个键的列名

② 修改表中的列为复合索引

create table t_test_index5(id bigint primary key auto_increment,name varchar(20),sno varchar(10),class_id bigint
);
alter table t_test_index5 add index(sno,class_id);

③ 单独创建索引并指定索引名

create table t_test_index6(id bigint primary key auto_increment,name varchar(20),sno varchar(10),class_id bigint
);
create index index_name on t_test_index6(sno,class_id);

6.删除索引

① 删除主键索引

语法 : alter table 表名 drop primary key;

注意 : 如果主键是自增列 , 需要先改为非自增 , 再删去主键

示例 :

alter table t_test_index6 modify id bigint;
alter table t_test_index6 drop primary key;

② 其他索引

语法 : alter table 表名 drop index 索引名;

示例 :

alter table t_test_index6 drop index index_name;

7.创建索引注意事项

  • 索引应该创建再高频查询的列上
  • 索引需要占用额外的存储空间
  • 对表进行插入,更新,删除操作时 , 同时也会修改索引 , 可能会影响性能
  • 常见过多或不合理的索引会导致性能下降 , 需要谨慎选择和规划索引

8.如何查看自己写的 SQL 走没走索引?

可以查看执行计划 , explain+查询语句

http://www.dtcms.com/a/553028.html

相关文章:

  • 2025年AI生成PPT工具评测:以“全链路一体化服务能力”为尺,ChatPPT再登顶
  • 天津特定网站建设推广搜素引擎优化
  • 直播美颜sdk特效功能架构全解析:从图像处理到AI渲染的技术演进
  • 2025强网杯web wp
  • 超融合架构下,如何智能调度让每台虚拟机都“跑得更快”?
  • 【Web应用安全】SQLmap实战DVWA SQL注入(从环境搭建到爆库,完整步骤+命令解读)
  • 从零打造 Telegram 中文生态:界面汉化 + 中文Bot + @letstgbot 搜索引擎整合实战
  • QT 给Qimage数据赋值,显示异常,像素对齐的坑
  • wordpress 整站下载万江做网站
  • 谈谈设计和建设网站体会摄影网站建设的功能有哪些
  • ESP 8684模组上的IO6引脚相关问题处理办法
  • 李宏毅机器学习笔记37
  • 大模型-Qwen-Agent框架:系列Agent功能介绍 (1)
  • 18. React的受控和非受控组件
  • cocos 在animation播放后调整widget右对齐能避免动画position影响对齐
  • RAG_混合检索
  • Pytorch 预训练网络加载与迁移学习基本介绍
  • 企业官网响应式网站作品网站
  • Ubuntu20.04操作系统搭建gitlab详细教程
  • MySQL:with窗口函数说明及使用案例
  • 【C++学习】对象特性--继承
  • 常州外贸网站浦东区建设工程监督网站
  • AI+产业革命:人工智能如何成为新质生产力的“第一加速器”
  • Linux应用开发-6-GPIO系统控制蜂鸣器
  • LeetCode 刷题【140. 单词拆分 II】
  • 网站开发 犯法网站漏洞扫描工具
  • 漏洞修复学习之CVE-2023-38545漏洞复现与修复
  • 逻辑回归特征重要性排序实验报告:不同特征选择方法的排序一致性验证
  • 深入解析MySQL(6)——存储过程、游标与触发器
  • Linux操作系统学习之---线程池