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

初识MYSQL —— 索引

前言

什么是索引?

索引就像给数据库加了 “目录”:

  • 只执行一条 create index,不用升级硬件、改代码或调 SQL,就能把查询速度从“翻整本书”变成“直接跳页”,成百上千倍地提速。
  • 代价是:每次插入、更新、删除都要同步维护这份 “目录”,带来额外磁盘 I/O,写操作明显变慢。

因此,索引最适合读多写少、数据量巨大的场景,用较小的写性能损失换取极大的读性能收益。

常见的索引:主键索引、唯一索引、普通索引和全文索引

存储介质特性

在链接索引之前,先回顾一下硬件磁盘(在博主文章深入了解linux系统—— 文件系统 有讲解磁盘)简单了解即可

1. 磁盘物理结构

  • 盘片与扇区
    • 数据保存在磁盘盘片的同心圆磁道上,最小物理单位是扇区(Sector)
    • 传统扇区大小:512字节(现代磁盘已有4KB扇区,但兼容模式仍表现为512字节)
    • 文件系统视角:多个连续扇区组成块(Block),Linux默认块大小为4KB
  • CHS定位法
    • 柱面(Cylinder):所有盘片相同半径的磁道集合
    • 磁头(Head):每个盘面对应一个磁头,编号唯一
    • 扇区(Sector):磁道上的分段编号
    • 通过CHS三元组可唯一定位任意扇区(硬件层面)
  • LBA线性地址
    • 系统软件使用逻辑块地址(LBA),屏蔽CHS的硬件细节
    • 操作系统自动完成LBA→CHS转换,实现硬件无关性

2. 磁盘访问模式

访问类型特征性能影响
连续访问两次IO扇区地址连续磁头移动距离短,效率高
随机访问两次IO扇区地址跳跃大需重新寻道,效率低

关键结论:磁盘随机IO是性能瓶颈,MySQL设计需尽量减少随机访问

MySQL数据库

1. 页(Page)机制

  • InnoDB页大小16KB(可配置为4KB/8KB/32KB,但16KB是默认最优值)
  • 与磁盘块的关系
    • 1个InnoDB页 = 32个传统扇区(512字节)或 4个现代扇区(4KB)
    • 预读机制:顺序访问时,磁盘控制器会自动预读相邻页,减少未来IO
  • 页结构优势
    • 局部性原理:一次IO加载16KB数据,可能覆盖后续查询所需记录
    • 减少随机IO:通过页合并写入(Batch Insert)降低磁盘刷新次数

2. 与文件系统交互

  • 双缓冲策略
    • InnoDB缓冲池(Buffer Pool):在内存中缓存热点页,默认大小为物理内存的80%
    • 操作系统页缓存(Page Cache):缓存磁盘块,可能重复缓存相同数据
    • 优化建议:启用O_DIRECT模式,绕过系统缓存,避免双重缓冲(需权衡稳定性)
  • 写操作路径
    1. 修改缓冲池中的页(变为脏页
    2. 后台线程按LRU顺序刷新到磁盘(非实时同步
    3. 通过**双写缓冲区(Doublewrite Buffer)**保证页写入原子性(防止半页写)

总结

  • 硬件抽象:通过LBA屏蔽CHS复杂性,实现跨平台兼容
  • 页机制:16KB页平衡了随机IO延迟顺序IO吞吐量
  • 缓存层次:Buffer Pool + 预读 + 批量刷新,最大化磁盘利用率
  • 写入优化:脏页异步刷新 + 双写缓冲,保证性能与一致性兼得

MYSQL中的数据文件,都是以page为单位保存在磁盘中的。

MYSQLCURD操作,都需要通过计算,找到对应的插入位置,或者对应要修改或者查询的数据。

任何计算都得先让数据进内存,CPU 只认内存,磁盘数据必须整页(16 KB Page)搬进内存才能用(MYSQL和磁盘交互的基本单位是16KB

批量用内存,一次换一块:MySQL 启动就划走一大片内存叫 Buffer Pool,专门缓存这些 16 KB 页;命中缓存就直接在内存里算,省去磁盘动作。

为了更高的效率,就要尽可能的减少系统和磁盘IO的次数。

理解索引

在了解索引具体是什么之前,先来看一种现象:

create table stu(id int primary key,age int,name varchar(10)
);
insert into stu values(3,18,'Tom');
insert into stu values(4,19,'Jack');
insert into stu values(1,20,'Lucy');
insert into stu values(5,19,'Lily');
insert into stu values(2,18,'Jerry');

在这里插入图片描述

可以看到,表stu中是存在主键的;这里无序插入5条记录,再使用select查询时,查询到的数据是有序的

这里在创建表时,不指明主键(MYSQL会创建新的一列作为主键,自增长),在查询到的数据顺序和插入数据的顺序是一样的。

理解单个page

MYSQL和磁盘交互(IO)是以page为单位的,在page中存储着数据;

MYSQL在从磁盘读取时,就会读取一个/多个page页;那在MYSQl中就势必会存在非常多的page页(一个数据表文件是由一个/多个page页组成的)。

MYSQL要管理这些page页,就势必存在相关的描述字段和数据结构(先描述、再组成)。

在这里插入图片描述

每一个page,在MYSQL中都是16KB大小,使用prevnect构成双向链表。

这里因为设置了主键,MYSQL会默认安装主键给我们的数据进行排序;数据是有序且彼此关联的。

理解多个page

通过上述描述,我们理解:在查询某条数据时将一个page页加载到内存中,减少IO的次数,来提高性能。

但是,数据在页内存储时真的如上述那样,单单使用链表结构吗?

如果有上千万条数据,就需要多个page页来保存,多个page页彼此之间使用双链表连接起来;在每一个page页内部的数据也是链表结构,那查找一条记录还是线性查找啊,效率太低的。

单个page

在平常看书时,书中存在目录,目录中存储了每一个章节对应的页码;

我们想要查看哪一个章节,就可以根据目录找到页码,快速的找到要看的章节。

目录,就是一直空间换时间的方案

在这里,是不是也可以存在一个目录呢,"目录"中存储中编号和指向对应记录的指针。

在这里插入图片描述

这里在查找数据时,就只需要遍历page页中的目录就可以判断出是否存在于当前page中。

所以,在创建表时指明主键,插入数据时MYSQL会自动安装主键进行排序,方便查询

计算没有指明主键,MYSQL也会新增一列作为主键(自增长),并且安装该列进行排序

多个page

上述在一个page页中加入目录,解决了在一个page页中查找目标记录的效率问题;

但是,一个page页大小只有16KB,随着数据量不断增大,就必定会有多个page页存储数据;

而在page之间,也是需要MYSQL遍历的,遍历也就意味着需要大量的IO;还是存在多次IO的效率问题。

解决方案:给page页也带上目录。

使用一个目录项来指向某一页,这个目录项存放的就是要执行的页中存放的最小数据的键值;

每一个目录项中都存储着对应page页存储数据的最小键值和指向对应page页的指针。

在这里插入图片描述

存在一个目录页来管理页目录,目录页中的数据存放的就是指向的那一页中最小的数据。有数据,就可通过比较,找到该访问那个Page,进而通过指针,找到下一个Page。

**目录页的本质也是页,普通页中存的数据是用户数据,而目录页中存的数据是普通页的地址 **

在这里插入图片描述

最底层的数据页通过链表连接

这不就是传说中的**B+树**

Innodb建立索引结构使用的数据结构是B+树。

在这里插入图片描述

B树和B+树的区别

  • B树节点既有数据、又有page指针,而B+树,只有叶子结点有数据;目录页,只有键值和page指针。
  • B+树叶子节点全部相连,而B树没有。

聚簇索引 VS 非聚簇索引

MYISAM存储引擎,同样使用B+树作为索引结构;

MYISAM最大的特点是,将索引page和数据page分离。(叶子节点不存储数据,只有对应数据的地址)

在这里插入图片描述

相比较于MYISAMInnoDB存储引擎则是将索引和数据放在一起的。

InnoDB这种将索引和数据放在一起的索引方案,叫做聚簇索引

MYSQL中,除了主键索引之外,我们也可以按照其他列信息建立索引,这种索引一般称为普通(辅助)索引;

  • 对于MYISAM存储引擎,建立普通索引和主键索引没有什么区别,就是主键不能重复,非主键可以重复(唯一键不能重复)

  • 而对于InnoDB存储引擎,在普通索引的叶子节点page中存储的是主键值而不是数据。

    通过普通索引,找到目标记录就要两次索引:先检索普通索引获取主键,然后再用主键到主键索引中检索到记录。(这个过程,就叫做回表查询

索引相关操作

1. 主键索引

创建主键索引,在创建主键时,MYSQL就会自动创建主键索引。

三种方式:

  1. 创建表时,指明主键字段(在字段名后 指定 primary key
create table test1(id int primary key,name varchar(10)
);
  1. 创建表时,指明主键字段(在创建表最后,指明一列/多列作为主键)
create table test2(id int,name varchar(10),primary key (id)
);
  1. 创建完表后,再添加主键
create table test3(id int, name varchar(10) );
alter table test3 add primary key (id);

2. 唯一索引

除了主键以外,在创建唯一键时,MYSQL也会为我们创建唯一索引。

三种方式:

  1. 创建表时,指明主键字段(在字段名后 指定 unique key
create table test4(id int primary key,name varchar(10) unique key
);
  1. 创建表时,指明主键字段(在创建表最后,指明一列/多列作为主键)
create table test5(id int,name varchar(10),primary key (id),unique key (name)
);
  1. 创建完表后,再添加主键
create table test6(id int primary key, name varchar(10) );
alter table test6 add unique key (id);
  • 一张表可以有多个唯一索引;
  • 如果在某一列建立唯一索引,必须保证这一列不能有重复数据;
  • 在唯一索引上指定not null,可以等价于主键索引

3. 普通索引

创建普通索引,也是有三种方式:在创建表时,指定索引;创建完表后,指定某列创建普通索引;以及创建指定索引名的索引。

  1. 创建表时,指定某列为索引
create table test7(id int primary key,name varchar(10),index(name)
);
  1. 创建完表后,指定某列为索引
create table test8(id int primary key, name varchar(10));
alter table test8 add index(name);
  1. 创建完表后,以指定列创建名为index_name的索引
create table test9(id int primary key, name varchar(10));
create index index_name on test9(name);
  • 一张表可以有多个普通索引。
  • 如果某列要创建索引,但是该列存储重复的值,就要使用普通索引。

4. 查询索引

查询索引相关信息

show keys from tb_name;
show index from tb_name;
desc tb_name;

在这里插入图片描述

5. 删除索引

  1. 删除主键索引
alter table tb_name drop primary key;
  1. 删除普通索引 方法1

删除普通索引,需要使用索引名,而索引名就是上述查询索引时Key_name字段。

alter table 表名 drop index 索引名;
  1. 删除普通索引 方法2
drop index 索引名 on 表名;

本篇文章到这里就结束了,感谢支持
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws

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

相关文章:

  • Blender快捷方式,自用Mark版
  • 移远 5G RG255AA-CN 调试
  • PyTorch3D从CUDA到CPU环境的完整迁移指南
  • 移动通信网络建设-实验2:5G站点选型与设备部署
  • 【自然语言处理】预训练06:子词嵌入
  • 地球的螺旋运动、四季轮回与椭圆轨道:统一场论下的宇宙新图景
  • html格式网站与网站开发有关的岗位是哪些
  • 底层视觉及图像增强-项目实践(十六-0-(6):线性映射技术在LED显示驱动中的工程实践与创新):从奥运大屏,到手机小屏,快来挖一挖里面都有什么
  • 2.7 模型评估与 A/B 测试
  • 政务终端一体化安全解决方案
  • 模板工程的建立
  • 开发者实践:电梯梯控的 非侵入式 与安全模块的电气解耦
  • Redis 高可用集群部署实战:单Docker实现1主2从3
  • 成都在线制作网站作文网入口
  • 想更新公司网站怎么做利于优化的wordpress模板
  • APP开发技术选型:原生 vs 跨端 (Flutter/React Native) 对比与适配场景
  • 智能指针在仓颉技术中的深度实践:从原理到架构的全维解析
  • Flutter开发全攻略:从入门到精通
  • Flutter持续健康发展的多维度分析
  • Flutter架构解析:从引擎层到应用层
  • 六大 API 架构风格
  • LoRA: Low-Rank Adaptation of Large Language Models及其反思
  • 搜索网站做淘宝客怎么在电脑上建立自己的网站
  • 股票投资方法论
  • SSE通信技术详解:Node.js实现服务器端事件推送
  • 广州市建设工程定额管理网站重写路由 wordpress
  • 有什么做兼职的医疗网站做网站应选那个主题
  • Visual Basic创建工具栏
  • IDEA的Code Style配置(使用google的Java Code Stytle)
  • 一个网站空间如何放两个网站内容