MySQL索引特性

文章目录

  • 为什么要有索引?
  • 认识磁盘
    • 磁盘的结构
    • 磁盘的盘片结构
    • 定位扇区
    • 磁盘随机访问 (Random Access)与连续访问 (Sequential Access)
  • MySQL与磁盘交互
  • 索引的理解
    • 测试主键索引
    • 索引的原理
    • 索引结构是否可以使用其他数据结构
    • B树 vs B+树
    • 聚簇索引 vs 非聚簇索引

为什么要有索引?

MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。

打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车。

索引的引入,使得查询速度的提高,这种提高是以插入、更新、删除的速度为代价的,这些写操作,增加了大量的IO。所以它的价值,在于提高一个海量数据的检索速度。

常见索引:

  • 主键索引(primary key)
  • 唯一索引(unique key)
  • 普通索引(index)
  • 全文索引(fulltext)

案例:构建一个海量数据表,来验证索引带来的查询差异性

drop database if exists `test_index`;
create database if not exists `test_index` default character set utf8;
use `test_index`;

-- 构建一个8000000条记录的数据

-- 产生随机字符串
delimiter $$
create function rand_string(n INT)
returns varchar(255)
begin
declare chars_str varchar(100) default
'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
declare return_str varchar(255) default '';
declare i int default 0;
while i < n do
set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));
set i = i + 1;
end while;
return return_str;
end $$
delimiter ;


-- 产生随机数字
delimiter $$
create function rand_num( )
returns int(5)
begin
declare i int default 0;
set i = floor(10+rand()*500);
return i;
end $$
delimiter ;

-- 创建存储过程,向雇员表添加海量数据
delimiter $$
create procedure insert_emp(in start int(10),in max_num int(10))
begin
declare i int default 0;
set autocommit = 0;
repeat
set i = i + 1;
insert into EMP values ((start+i)
,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());
until i = max_num
end repeat;
commit;
end $$
delimiter ;

-- 雇员表
CREATE TABLE `EMP` (
  `empno` int(6) unsigned zerofill NOT NULL COMMENT '雇员编号',
  `ename` varchar(10) DEFAULT NULL COMMENT '雇员姓名',
  `job` varchar(9) DEFAULT NULL COMMENT '雇员职位',
  `mgr` int(4) unsigned zerofill DEFAULT NULL COMMENT '雇员领导编号',
  `hiredate` datetime DEFAULT NULL COMMENT '雇佣时间',
  `sal` decimal(7,2) DEFAULT NULL COMMENT '工资月薪',
  `comm` decimal(7,2) DEFAULT NULL COMMENT '奖金',
  `deptno` int(2) unsigned zerofill DEFAULT NULL COMMENT '部门编号'
);


-- 执行存储过程,添加8000000条记录
call insert_emp(100001, 8000000);

上面的sql创建了test_index数据库,test_index中有一个含有8000000条记录的EMP表,select * from EMP limit 10 查看部分数据:

在这里插入图片描述

desc EMP;查看表结构,EMP表没有创建任何索引:

在这里插入图片描述

尝试查询EMP表的记录:

在这里插入图片描述

可以发现查询EMP表的记录,由于数据量很大而且EMP没有建立任何索引,每次都需要较长的时间进行查询。

为EMP表建立索引:

在这里插入图片描述

由于数据量很大,EMP表在创建索引需要花费较长的时间。
创建索引后尝试查询:

在这里插入图片描述
可以发现,索引大大提高了数据库表的查询速度。


认识磁盘

MySQL 给用户提供存储服务,而存储的都是数据,数据在磁盘这个外设当中。 磁盘是计算机中的一个机械设备,相比于计算机其他电子元件,磁盘效率是比较低的,在加上IO本身的特征,如何提高效率,是 MySQL 的一个重要话题。

磁盘的结构

在这里插入图片描述

磁盘的盘片结构

在这里插入图片描述

在MySQL中创建数据库,本质上是在Linux下创建特定目录,在MySQL中创建数据库表,本质上是在特定的目录下创建特定的文件。数据库文件,本质上就是保存在磁盘的盘片中,也就是上图的一个个小格子中,即扇区。所以找到一个数据库文件,本质上就是在磁盘上找到对应的扇区,就需要能够定位某个盘片中的某些扇区。


定位扇区

在这里插入图片描述

  • 柱面(磁道): 多盘磁盘,每盘都是双面,大小完全相等。那么同半径的磁道,整体上便构成了一个柱面
  • 每个盘面都有一个磁头,那么磁头和盘面的对应关系便是1对1的

定位文件在扇区中的位置,需要知道磁头(Heads)、柱面(Cylinder)(等价于磁道)、扇区(Sector)对应的编号,即可在磁盘中定位所要访问的扇区,这种磁盘定位方式叫做CHS。在实际上硬件使用的是CHS定位方式,但是软件所用的是LBA定位方式,这是一种线性地址,可以抽象成虚拟地址和物理地址的关系,系统会将LBA地址转化成CHS地址,交给硬盘进行数据处理。

❔ 在硬件层面上,我们已经可以定位某一个扇区,那么系统软件和磁盘进行IO交互也是按照扇区(512KB)来进行的吗

  • 系统软件和磁盘进行IO交互不是按照扇区(512KB)进行交互的
  • 如果系统直接使用硬件提供的数据大小进行交互,那么系统的IO代码就和硬件强相关,如今硬件的发展日新月异,换言之,如果硬件发生变化,系统代码就必须大规模更改,维护成本大
  • 512byte作为单次IO的大小太小了,这就意味着系统需要重复读取相同大小的数据,需要多次访问磁盘,效率较低
  • 文件系统中,物理内存实际上是被分为一个个4KB的数据块的,文件系统读取磁盘的基本单位,不是扇区,而是数据块,基本单位是4KB

磁盘随机访问 (Random Access)与连续访问 (Sequential Access)

  • 随机访问:本次IO所给出的扇区地址和上次IO给出扇区地址不连续,这样的话磁头在两次IO操作之间需要作比较大的移动动作才能重新开始读/写数据。
  • 连续访问:如果当次IO给出的扇区地址与上次IO结束的扇区地址是连续的,那磁头就能很快的开始这次IO操作,这样的多个IO操作称为连续访问。

因此尽管相邻的两次IO操作在同一时刻发出,但如果它们的请求的扇区地址相差很大的话也只能称为随机访问,而非连续访问,因为连续访问的连续指的是物理上的连续,而不是时间上的连续。磁盘是通过机械运动进行寻址的,连续访问不需要过多的定位,故效率比较高。


MySQL与磁盘交互

MySQL作为一款应用软件,可以想象成是一种特殊的文件系统,它有着更高频的IO场景,因此为了提高基本的IO效率,MySQL与磁盘交互的基本单位是16KB,这个基本数据单元在MySQL这里也叫做Page

show global status like 'innodb_page_size查看page大小

在这里插入图片描述

在MySQL进行CRUD时,是需要计算数据的位置的,涉及到计算就需要CPU的参与,根据冯诺依曼体系结构,CPU只和内存打交道,因此MySQL访问数据,不可能直接和磁盘交互,全部需要加载到内存进行访问。

数据库的数据是可能同时存在于内存和磁盘中的,数据在进行CRUD之后发生更改,就需要有对应的刷新策略将数据刷新到磁盘,这就说明MySQL需要较高频次的进行IO操作,为了提高效率,MySQL服务器会在内存中预先开辟一大块空间进行数据缓存,这块空间叫做buffer pool,磁盘的数据会预先加载到buffer pool中,刷新磁盘的数据也是从buffer pool中将数据刷新到磁盘。

数据是不会直接从内存刷新到磁盘的,它们的交互会经过操作系统,操作系统有对应的内核级缓冲区,当MySQL需要从磁盘上加载数据时,数据会先通过磁盘和内核缓冲区进行每次4KB的IO交互,操作系统再通过对应刷新策略,数据从内核缓冲区以每次16KB的IO交互拷贝到buffer pool中。

简化图:

在这里插入图片描述


索引的理解

测试主键索引

建立测试表:

在这里插入图片描述

插入多条记录:

在这里插入图片描述

查看插入结果:

在这里插入图片描述


索引的原理

可以发现,插入数据的时候并没有按照主键的顺序进行插入,但是插入多条数据后,结果默认就是有序的,这是为什么?

MySQL中需要管理很多的数据,管理这些数据就需要先描述,再组织,MySQL中有一个个的Page结构体,用来存放数据,MySQL中存在很多Page结构体,它们通过两个指针构成双向链表。

伪代码:

struct Page 
{
	struct Page* page_prev;
	struct Page* page_next;
	char buffer[]
};

在这里插入图片描述

在插入数据时排序,是为了优化链表增删改效率高,查询效率低的特点。但是当Page内的数据越来越多时,在页内查找也还是线性查找,于是数据库在插入时,进行排序,是为了便于建立Page中的目录。在单个Page中引入页内目录,将Page中数据分为若干区域,目录中存储这些区域中主键的最小值。
引入目录后,MySQL在进行查找时,预先查找目录中的内容,对于插入数据的主键处于目录的哪一个区间,从而到区间中查找,大大提高了在单个Page中查找数据的效率。

在这里插入图片描述

MySQL在单个Page中引入目录,大大提高了再单个Page中的查找效率,但是当数据量很大时,MySQL中存在很多Page,这些Page也是通过链表的形式连接起来的,所以在数据量很大时,在多个Page中查找也是线性遍历。

在这里插入图片描述

MySQL是怎么处理这种情况,提高效率的呢

按照单个Page内创建目录的思路,给多个Page也带上目录,每一个目录项的构成是 Page中最小主键值 和 指向该Page的指针,与页内目录不同,这个目录管理的级别是Page页,页内目录管理的级别是一条记录

在这里插入图片描述

当第二层的Page逐渐增多时,可以再添加一层Page管理下层Page,依次类推,就构成了B+树的结构。通过B+树的结构,可以提高查找的效率,减少将过多Page加载到内存中,减少和磁盘的IO次数。

总结:

  • Page分为目录页和数据页。目录页只放各个下级Page的最小键值
  • 查找的时候,自定向下找,只需要加载部分目录页到内存,即可完成算法的整个查找过程,大大减少了IO次数

索引结构是否可以使用其他数据结构

❔ InnoDB 在建立索引结构来管理数据的时候,其他数据结构为何不行

  • 链表:查找是线性遍历
  • 二叉搜索树:可能退化成链表的线性结构,查找是线性遍历
  • AVL数和红黑树:虽然树形结构是平衡或者近似平衡的,但是该结构还是二叉树结构,这就意味着AVL树和红黑树的结构会比较高,查询数据是自顶向下查找,这就意味着要遍历更多的结点,就需要经历多次IO

在这里插入图片描述


B树 vs B+树

B树:
在这里插入图片描述
B+树:
在这里插入图片描述

  • B树节点,既有数据,又有Page指针,而B+只有叶子节点有数据,其他目录页,只有键值和Page指针
  • B+树叶子节点是以链表连接起来的,而B树没有相连

为什么选择B+树

  • B+树的结点中只有叶子结点存储数据,而B树的全部结点都存储数据,这样一来,B+树的高度比B树的高度要低,查找的次数也会减少
  • B+树的结点以链表的形式相连,B树没有,在范围查找的时候,B+树的效率比B树高

聚簇索引 vs 非聚簇索引

MyISAM 引擎同样使用B+树作为索引结果,叶节点的data域存放的是数据记录的地址。下图为 MyISAM 表的主索引,Col1 为主键。

在这里插入图片描述

其中, MyISAM 最大的特点是,将索引Page和数据Page分离,也就是叶子节点没有数据,只有对应数据的地址。相较于 InnoDB 索引, InnoDB 是将索引和数据放在一起的

下图是InnoDB索引结构,以Col3为主键:

在这里插入图片描述
其中, InnoDB 这种用户数据与索引数据在一起索引方案,叫做聚簇索引,MyISAM 这种用户数据与索引数据分离的索引方案,叫做非聚簇索引。

测试:

在这里插入图片描述

  • innodb_test.frm: 存放的是表结构数据
  • innodb_test.ibd: 存放的是索引和用户数据

在这里插入图片描述

  • myisam_test.frm: 存放的是表结构数据
  • myisam_test.MYD: 存放的是表的用户数据
  • myisam_test.MYI: 存放的是表的索引数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/1374.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于深度学习的犬种识别软件(YOLOv5清新界面版,Python代码)

摘要&#xff1a;基于深度学习的犬种识别软件用于识别常见多个犬品种&#xff0c;基于YOLOv5算法检测犬种&#xff0c;并通过界面显示记录和管理&#xff0c;智能辅助人们辨别犬种。本文详细介绍博主自主开发的犬种检测系统&#xff0c;在介绍算法原理的同时&#xff0c;给出Py…

分布式微服务架构下网络通信的底层实现原理

在分布式架构中&#xff0c;网络通信是底层基础&#xff0c;没有网络&#xff0c;也就没有所谓的分布式架构。只有通过网络才能使得一大片机器互相协作&#xff0c;共同完成一件事情。 同样&#xff0c;在大规模的系统架构中&#xff0c;应用吞吐量上不去、网络存在通信延迟、我…

Qt音视频开发26-监控画面各种图形绘制设计

一、前言 视频监控系统做到后面&#xff0c;逐渐需要搭配人工智能算法&#xff0c;将算法计算后的信息以OSD标签以及方框各种图形的信息显示到视频中&#xff0c;这种当然和OSD一样也是有两种方式&#xff0c;一种是源头就贴好了&#xff0c;一种是将结果发给软件这边解析绘制…

专项攻克——死锁

文章目录O、死锁定义一、 常见的java死锁代码1. synchronized等待对象释放&#xff0c;导致死锁2. CountDownLatch计数等待&#xff0c;导致死锁二、怎么避免死锁2.1 死锁的四个必要条件2.2 避免死锁2.3 常见的避免死锁技术三、java程序出现死锁&#xff0c;怎么解除&#xff1…

Vue使用的编辑器

作者简介&#xff1a;一名计算机萌新、前来进行学习VUE,让我们一起进步吧。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;我叫于豆豆吖的主页 目录 前言 一.vue常用的IDE工具Visual Studio Code 3. 汉化教程 4.常用快捷键 5. Visual Studio C…

瑞萨Renesas RA2L1 开发板测评(1)--keil环境配置

前言&#xff08;1&#xff09;首先感谢李肯前辈的活动&#xff0c;从而申请到了RA2L1开发板的测评。&#xff08;2&#xff09;本文将会简单介绍此开发的Renesas RA2L1 开发板的前期配置。需要注意的是&#xff0c;MDK版本要5.30 以上。MDK下载链接&#xff1b;&#xff08;3&…

计算机中的浮点数运算

计算机中的浮点数 计算机中以固定长度存储浮点数的方式&#xff0c;造成了浮点数运算过程容易产生上溢和下溢。以float32为例, 其标记位占1bit,指数位占8bit,小数部分占23bit 经典下溢场景 不满足精度导致截断误差 #include <iostream> #include <iomanip> usin…

一行代码“黑”掉任意网站

文章目录只需一行代码&#xff0c;轻轻一点就可以把任意网站变成暗黑模式。 首先我们先做一个实验&#xff0c;在任意网站中&#xff0c;打开浏览器开发者工具(F12)&#xff0c;在 C1onsole 控制台输入如下代码并回车&#xff1a; document.documentElement.style.filterinve…

Hive 数据倾斜

数据倾斜&#xff0c;即单个节点任务所处理的数据量远大于同类型任务所处理的数据量&#xff0c;导致该节点成为整个作业的瓶颈&#xff0c;这是分布式系统不可能避免的问题。从本质来说&#xff0c;导致数据倾斜有两种原因&#xff0c;一是任务读取大文件&#xff0c;二是任务…

【MIT 6.S081】Lab2: system calls

本Lab包括两个简单系统调用的实现&#xff0c;进一步熟悉系统调用接口。 笔者用时约1.5h 概述 根据文档说明&#xff0c;当我们添加一个系统调用时&#xff0c;比如第一个任务是添加一个trace&#xff0c;需要进行以下操作&#xff1a; 首先将系统调用的原型添加到user/user…

博客系统实现自动化测试

目录 一、设计博客系统的测试用例 二、利用测试用例进行测试 测试登录页面 界面测试 功能测试 测试博客列表页 界面测试 功能测试 测试博客详情页 界面测试 功能测试 博客编辑页测试 界面测试 功能测试 一、设计博客系统的测试用例 二、利用测试用例进行测…

【Java版oj】day12二进制插入、查找组成一个偶数最接近的两个素数

目录 一、二进制插入 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 二、查找组成一个偶数最接近的两个素数 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff0…

One-YOLOv5 v1.2.0 Released(支持分类,检测,实例分割)

0x0. 引言0x1. 快速开始0x2. 在COCO上的精度表现 yolov5s-defaultyolov5s-seg 0x3. 在COCO上的单GPU性能表现特性 & bug 修复 特性用户反馈的bug 下个版本的展望附件常用预训练模型下载列表 0x0. 引言 &#x1f31f; v1.2.0同步了ultralytics yolov5的上游分支v7.0 &…

前端入门:HTML5+CSS3+JAAVASCRIPT

1、 初识HTML HTML:Hyper Text Markup Language(超文本标记语言) 。 超文本包括&#xff1a;文字、图片、音频、视频、动画等。 1.1、W3C标准 1.2、HTML基本结构 示例&#xff1a; <!-- DOCTYPE:告诉浏览器&#xff0c;我们要使用什么规划&#xff0c;这里是HTML --> …

IDAFrida

IDA&Frida 前言 偶然间发现了一本秘籍《IDA脚本开发之旅》&#xff0c;这是白龙的系列文章&#xff0c;主要是安卓平台&#xff0c;笔者只是根据他的知识点学习&#xff0c;拓展&#xff0c;可以会稍微提及别的平台。本文并不会贴出他的思路分析&#xff0c;只对于源码进…

C语言实现单链表(超多配图,这下不得不学会单链表了)

目录 一&#xff1a;什么是链表&#xff1f; 二&#xff1a;创建源文件和头文件 (1)头文件 (2)源文件 三&#xff1a;实参和形参 四&#xff1a;一步步实现单向链表 &#xff08;1&#xff09;建立一个头指针并置空 &#xff08;2&#xff09;打印链表&#xff0c;便于…

*p++,*(p++),*++p,(*p)++区别?

*p++:等同于:*p; p += 1; 解析:由于和++的运算优先级一样,且是右>结合。故p++相当于*(p++),p先与++结合,>然后p++整体再与结合。前面陈述是一种最 常见的错误,很多初学者也是这么理解的。 但是,因为++后置的时候,本身含义就是先 运算后增加1(运算指的是p++作为…

GPT-4最震撼我的一点

昨天我看了一遍OpenAI发的视频和论文&#xff0c;最震撼我的并不是根据手绘草图生成HTML页面代码&#xff0c;因为草图太简单&#xff0c;对于复杂的有交互的界面&#xff0c;还不知道它的能力究竟如何&#xff0c;能不能生成准确的、清晰的代码&#xff0c;我再实验一下再给大…

C实现栈及OJ题有效的括号

文章目录栈概念及基本操作源码OJ题括号匹配栈概念及基本操作 栈也同链表和顺序表一样是一种线性表只是比较特殊而已&#xff0c;栈遵循一种先进后出的原则,其实栈就像生活中的叠盘子一样&#xff0c;将盘子一个一个的叠起来&#xff0c;每次都只能在最顶层叠&#xff0c;然后取…

ElasticSearch快速入门详解(亲测好用,强烈推荐收藏)

3.快速入门 接下来快速看下elasticsearch的使用 3.1.概念 Elasticsearch虽然是一种NoSql库&#xff0c;但最终的目的是存储数据、检索数据。因此很多概念与MySQL类似的。 ES中的概念数据库概念说明索引库&#xff08;indices)数据库&#xff08;Database&#xff09;ES中可…