MySQL性能优化一 底层数据结构与算法

news2025/1/16 2:40:58

一 索引

索引
MySQL官网解释:索引是帮助MySQL高效获取数据的排好序数据结构

索引数据结构:

  • 二叉树
  • 红黑树
  • Hash表
  • B-Tree

案例:有一张两列七行的一个表t
在这里插入图片描述
假如我们的查找sql语句是:

select * from t where t.col2=89;

正常情况下,需要一行一行取出来col2的值,然后与89进行比对,直到找到为止;

MySQL一张表里的数据,多行数据不一定是在磁盘里挨着存储的(因为假如存了一行数据后,几天后才存第二行数据,中间的时间段里可能会有其他数据存入磁盘),是随机存放的;执行一条查询sql语句(假如表里数据很多),每次从磁盘里取一条数据,都需要与磁盘做一次I/O读取交互,取出数据后做比对看是不是自己需要的数据,这样性能非常低下;我们的目的是,减少查找我们需要的数据时与磁盘的交互次数(减少查找次数),只要把这个次数控制在一定范围内,效率就会提升很多;此时,索引就诞生了;

如下,给col2做索引,前边已经提到了,索引就是一个数据结构,比如二叉树

二叉树
那我们把col2这列数据放在二叉树(左子节点小于父节点、右子节点大于父节点)里即可,如下:
在这里插入图片描述
查找89的话,只查找两次即可查到;第一次拿到34,发现不是我们要找的数据,且我们要找的数据大于34,应该在34右子节点查找,第二次即可找到89;

上图树中,每个节点存放key/value,其中key存放的是col2字段对应的值(34、77…89、23),value存放的是索引所在行的磁盘文件地址;

其实MySQL索引底层用的不是二叉树,原因如下

如果我们的查询col1的语句是这样的:

select * from t where t.col1=6;

如果是二叉树的话,那么col1对应的二叉树就是这样的:

在这里插入图片描述

此时的二叉树相当于变成了链表,查找col1=6的次数还是6次,没有提升查询效率;
即如果索引使用二叉树的话,遇到这种列的数据是递增的数据,二叉树就不会起到作用,所以索引底层没有用二叉树做;

红黑树
红黑树也叫二叉平衡树,有把树自动平衡的功能,col1对应的红黑树如下:
在这里插入图片描述
此时,查找col1=6的次数为3次;

MySQL索引底层用的也不是红黑树,原因如下:
树的高度的限制:当表的数据量太大,比如500w,那树的高度就非常高了,比如树高度达到了20,并且要查的数据位于最下边的叶子节点,至少需要20次查找,要做20次磁盘IO;所以我们要做的是把树的高度降下来,比如高度<=4,或者高度<=3等,我们是可以接受的——B树;

B树

  • 叶节点具有相同的深度,叶节点的指针为空
  • 所有索引元素不重复
  • 节点中的数据索引从左到右递增排列

之前的红黑树只有一个根节点,B树有多个跟节点(水平扩展)
在这里插入图片描述
MySQL索引底层也没有用纯粹的B树,而是对B树做了优化,即B+树

B+Tree(BTree变种)

  • 非叶子节点不存储data,只存储索引(冗余),可以放更多的索引(即叶子结点里包含了表里所有的索引元素)
  • 非叶子节点称为冗余索引,非叶子节点从叶子节点得到一些数据后,构建起来B+树(即非叶子节点就是为了构建B+树的)
  • 叶子节点包含所有索引字段
  • 叶子节点之间用指针连接(B树没有指针),存储着当前节点在磁盘上的位置,提高区间访问的性能

下边每一行我们称之为一页

在这里插入图片描述
MySQL索引底层用的就是B+树;
假如我们查找的col1=30,会先把根节点这一页(15、56、77)全部load到内存(RAM)里去(相对比较耗时),然后把30和内存里的这几个数据做比对(相对不耗时),假如使用二分查找快速定位到30是位于15~56之间;然后就把15这页数据(15、20、49)也加载到内存里,与30进行比对…;

那为什么不去掉其他节点,只留叶子结点,把所有的数据都放在叶子结点里,然后把叶子节点一次性load到内存里,直接把30和内存里的数据做折半查找呢?这样数据量大的话,内存容易撑爆;

每一页的大小大概16K

#查看mysql页大小:16384字节——16KB
SHOW GLOBAL STATUS  LIKE 'Innodb_page_size'

B+树放满后可以存放的数据量大概是多少?
为什么是16KB?
假如使用bigInt类型(8bit),则每一个索引占8bit,而上图中15和16中间存的是下一行(页)的地址(15、20、49的地址),这个地址占6bit;则一页数据16KB放满后,可以放的索引元素个数:16kb/(8+6)b=1170; 叶子结点特殊一些,就拿15这个叶子节点来说,data里存的可能是15这个索引所在磁盘空间地址,也可能存的是所在行的所有的其他列,data数据可能比较大,假如放的是一行数据,撑死了也就1kb(一行记录一般不会超过1kb),则这个叶子节点大概可以放的数据量为:1kb/(8+6)b=16(由于一般达不到1kb,所以得出的16这个值是假设的值,并不是在这里真正计算出来的);

综上,当B+树被放满后,可以放的索引数据量为:
1170X1170X16=21,902,400,即两千多万条;而树的高度仅仅是3,即3次IO就找到数据了;

MySQL的根节点其实是直接在内存里的(根节点常驻内存,即上图的15、56、77在最开始的时候就已经在内存里了),也就是说其实不是3次IO,而是2次;MySQL高版本后,把所有非叶子节点都放到了内存里了,这样就更快了;

为什么MySQL索引底层使用了B+树,而不是B树?
上边已经说了,B+树存储2000万条数的话,树高度只有3;如果是B树呢?
B树如下:
在这里插入图片描述

每一个data最大1kb,而每一页是16kb,所以每页(行)数据只能放16个索引元素,即16的n次方要达到2000万,这个n就是树的高度;很明显,n这个高度远远大于B+树的高度3;

表和索引是存储在磁盘里的,如果没有改配置的话,默认存的地方是:
在这里插入图片描述
在这里插入图片描述

二 MySQL表的存储引擎

2.1 存储引擎介绍

存储引擎是使用数据库的还是使用数据库表的?是数据库表的。

我们使用MySQL的Navcat建表的时候可以选择存储引擎,如下:
在这里插入图片描述
一般选择的存储引擎是InnorDB,早期版本使用MyISAM存储引擎
在这里插入图片描述

2.2 MyISAM存储引擎(已经不用了)

新建一张表,使用MyISAM做存储引擎,如下
在这里插入图片描述

  • .frm: 存放数据表结构的信息(frame框架简称)
  • .MYD: 存放数据(MY即MyISAM首字母,D是DATA)
  • .MYI: 存放索引(MY即MyISAM首字母,I是index索引)

MyISAM索引文件和数据文件是分离的(非聚集)

在这里插入图片描述
假如查的条件如下

select * from t where t.col1=30;

MySQL会先去MYI文件索引树里定位到索引元素为0xF3,然后根据0xF3在磁盘文件地址,在MYD文件里找到数据在磁盘里的一行数据;

2.3 InnorDB存储引擎

新建一张表,使用InnorDB做存储引擎,如下

  • .frm: 存放数据表结构的信息(frame框架简称)
  • .ibd: 存放数据和索引()

InnoDB索引实现(聚集)

  • 表数据文件本身就是按B+Tree组织的一个索引结构文件
  • 聚集索引-叶节点包含了完整的数据记录

在这里插入图片描述
上图可知,叶子结点存放了当前所在行的其他列的数据,如15这个节点存放了15所在行的所有其他列的数据34、Bob等(聚集索引);

即InnoDB的数据和索引在同一棵树里(同一个文件、聚集索引),而MyISAM是不在同一棵树里的(非聚集索引);

聚集索引与非聚集索引查找起来哪个快?
聚集快,因为聚集索引不需要跨文件查找;

为什么建议InnoDB表建主键,并且推荐使用整型的自增主键?

ibd文件必须要用一棵B+树来组织,那这个B+树从哪里来呢?如果表里自带主键的话,那就直接使用这个主键这列数据来构建B+树的整个表的数据。没有主键呢?没有主键的话,会从第一列开始,去选择一列数据都不重复的列作为主键,用这列数据来组织成一棵B+树;如果没有选到符合条件的列呢(没有一列数据是都不相等的)?那MySQL会新建立一个隐藏列,这个隐藏列会维护一个唯一id,来组织整张表的数据;

综上:我们建了主键后,就不需要那么麻烦了,不需要MySQL做那么多额外工作了;

那为什么推荐主键要使用整形且自增的呢?

整形原因

  • 在找索引的时候,在B+树这棵树里要进行比大小的操作,而uuid是字符串,比大小要通过ASSIC码先后顺序来比较,且要逐个字符来比,所以整形效率高;
  • 而且整形占用空间相对小很多;

自增原因
先来了解一下Hash结构

建索引的时候默认是B+Tree,也可以选择Hash结构
在这里插入图片描述
Hash结构

  • 对索引的key进行一次hash计算就可以定位出数据存储的位置
  • 很多时候Hash索引要比B+ 树索引更高效
  • 仅能满足 “=”,“IN”,不支持范围查询
  • hash冲突问题

表如下
在这里插入图片描述

把col3作为hash索引的话,当插入一条数据的时候,会对这个数据做一个hash算法(md5等很多种算法),得到的hash值放进hash桶里(hash数组),得到的hash值一样的话就就是hash冲突了,则生成一个链表来存hash值一样的数据;例如我们要查找name=Alice的一行数据,先对Alice做hash运算,得到hash值再去对应的链表里进行遍历;链表里的每个节点除了存放索引元素外,还存放了索引所在行的磁盘文件地址;
在这里插入图片描述
貌似这种hash查找更快一点;那为什么不用Hash结构,而要用B+树呢?主要是因为hash不支持=、in、范围查询;B+树在叶子结点有一个双向指针,且B+树是排好序的,所以支持范围查询;

非自增:新增数据的时候,会导致节点分裂,然后对树做一个平衡;
自增:新增数据的时候,不会分裂节点,会再新起一个节点;

为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)
如下,对col3做索引后,叶子节点Alice存储了主键值18
在这里插入图片描述
二级索引先找到主键索引,然后通过主键索引再找到具体的数据(二级索引有回表操作);

三 联合索引(复合索引)

一张表不推荐建立多个单值索引;一般通过建立2~3个联合索引,把80%以上的查询sql语句都覆盖到;

建立三个字段的联合主键索引:name、age、position
在这里插入图片描述

会按照索引建立的先后顺序,来排序,先比较name,再比age,再比position来决定先后顺序,排序后放在索引树里;
如name是字符串类型,那就按照Assic比较每一个字符,当通过name能排好序的话,就不看age和position了;name都一样(都叫Bill),那就比较age,age一样的话,就比较position,由于是联合主键,所以这里这三个字段不可能同时相等;

索引最左原理

在上边建立联合索引的前提下,下边哪条语句会走索引?

# 走索引
1 SELECT * FROM employees WHERE name = 'Bill' and age = 31;
# 不走索引
2 SELECT * FROM employees WHERE age = 30 AND position = 'dev';
# 不走索引
3 SELECT * FROM employees WHERE position = 'manager';

对于联合索引,一定要按照建立索引的顺序去使用;那为什么要有索引最左原理,为什么要按照name、age、position的查询顺序才会走索引?

数据插入索引树里是排好序的,而排序规则就是按照建索引时name、age、position的顺序来的;

假如我们不符合最左原则,直接查age=30,在整张表里,age不是排好序的了,所以索引没有起到作用,需要整张表全表扫描;
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql process 问题,kill不用的process

这个一般会出现在连接池中&#xff0c;导致连接池数量不够然后连接失败&#xff0c;所以要kill 我们kill的都是sleep的&#xff0c;就是没有释放但是不用的链接 前言 sql中的show full processlist是查看线程&#xff0c;实际就是查这个表 select * from information_schema.…

16S全长测序解密转基因玉米根瘤菌群落组成

论文题目&#xff1a; Deciphering the rhizobacterial assemblages under the influence of genetically engineered maize carrying mcry genes 期刊&#xff1a; Environmental Science and Pollution Research 研究背景 玉米是我国的重要粮食作物&#xff0c;但虫害和草…

2023大厂招聘岗位数预测!明年哪些公司可以去?

winter is coming&#xff01;这一年C端要见顶、K12被团灭、阿里被监管&#xff0c;滴滴被处罚、华为都在力求在寒气中活下来&#xff0c;连大厂都深陷泥沼&#xff0c;更别说中小企业。 太多因素导致大批裁员&#xff0c;前不久&#xff0c;互联网er最后的梦乡虾皮大量裁员&am…

智能车|直流电机、编码器与驱动器

智能车|直流电机、编码器与驱动器直流电机直流电机原理减速器编码器编码器简介编码器的工作原理四倍频采集编码器采集程序实现驱动器TB6612FNG 电机驱动器TB6612FNG 的主要参数引脚说明电机整体接线直流电机 直流电机&#xff08;direct current machine&#xff09;是指能将直…

JDK19都出来了~是时候梳理清楚JDK的各个版本的特性了【JDK18特性讲解】

JDK各个版本特性讲解-JDK18特性 一、JAVA18概述 Java 18 在 2022 年 3 月 22 日正式发布&#xff0c;Java 18 不是一个长期支持版本&#xff0c;这次更新共带来 9 个新功能。 https://openjdk.org/projects/jdk/18/ 二、具体新特性 1. 默认UTF-8字符编码 JDK 一直都是支持 UT…

SAP ABAP——SAP简介(四)【SAP GUI】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

Docker学习笔记——收藏

Docker 命令&#xff1b;Docker进程相关命令&#xff1b;Docker 镜像相关命令&#xff1b;Docker 容器数据卷&#xff1b;Docker 应用部署案例&#xff1b;Dockerfile&#xff1b;Docker 私有仓库搭建&#xff1b;笔记 目录 初始Docker 安装Docker Docker 架构 Docker 命令 …

圣诞也要撸代码 |【消息中间件MQ系列】Spring整合kafka并设置多套kafka配置

1、前言 圣诞节的到来&#xff0c;程序员不会收到圣诞老人的&#x1f381;&#xff0c;但可以自己满足一下自己&#xff0c;所以&#xff0c;趁着有时间&#xff0c;就记录一下这会儿撸了些什么代码吧&#xff01;&#xff01;&#xff01; 因为业务原因&#xff0c;需要在系统…

事务日志undo log

事务日志undo log 1 Undo日志的作用 作用1&#xff1a;回滚数据 逻辑上恢复&#xff0c;之前插入了一条数据&#xff0c;已经开辟了物理空间&#xff0c;回滚只是将该数据删除&#xff0c;物理空间还存在。 作用2&#xff1a;MVCC 2 Undo存储结构 mysql> show variables …

java生成SSL证书并添加信任,tomcat配置https访问并解决扫描漏洞问题

一、java生成keystore密钥对 1、打开jdk的bin目录&#xff0c;使用keytool工具生成keystore密钥对 Keytool 是一个 Java 数据证书的管理工具 &#xff0c;Keytool 将密钥&#xff08;key&#xff09;和证书&#xff08;certificates&#xff09;存储于一个称为 keystore 的密…

某车企用户数据泄露,新能源汽车信息安全问题不容忽视

某车企&#xff1a;公司核心数据被窃取 12月20日&#xff0c;国内某新能源汽车发布相关声明称&#xff0c;2022年12月11日&#xff0c;其收到外部邮件&#xff0c;声称拥有该车企内部数据&#xff0c;并以泄露数据勒索225万美元等额比特币&#xff08;约合1570.5万元人民币&am…

FFmpeg学习笔记--Ubuntu20.04编译安装FFmpeg、FFplay和FFprobe

目录 1--下载FFmpeg 2--编译FFmpeg 3--设置环境变量 4--测试 1--下载FFmpeg ① 下载 5.1 版本的 ffmpeg wget http://www.ffmpeg.org/releases/ffmpeg-5.1.tar.gz ② 解压下载的压缩包 tar -zxvf ffmpeg-5.1.tar.gz 2--编译FFmpeg ① 进入解压后的文件夹 cd ffmpeg-5…

基于JAVA Spring Boot高颜值的教学管理平台(含小程序),提供权限管理、考试、问卷、练习、在线学习等功能

Welcome to sg-exam-next &#x1f44b; 硕果云&#xff0c;基于Spring Boot搭建的方便易用、高颜值的教学管理平台&#xff0c;提供权限管理、考试、问卷、练习等功能 主要功能为在线学习、考试、练习 课程内容支持图文、视频&#xff0c;考试类型支持考试、练习、问卷 题型支…

Android插件化技术——【class学习】

class 文件的定义 class 文件就是能够被 JVM 识别&#xff0c;加载并且执行的文件格式。从定义来看&#xff0c;class 文件没有想象中的那么神秘&#xff0c;和其他格式如 txt&#xff0c;mp4 一样&#xff0c;只是一种文件格式&#xff0c;它存储的是我们应用程序。 不止 Ja…

matlab/simulink中关于如何使得信号FFT和IFFT前后功率保持一致

快速傅里叶变换FFT其实是一种对离散傅里叶变换DFT的快速算法 为了便于公式推导和理解&#xff0c;本文从DFT的公式出发进行解释&#xff0c;在帕萨瓦尔定律的条件下&#xff0c;探究如何保证FFT/IFFT前后信号功率保持一致。 目录模型假设FFT前后功率保持一致IFFT前后功率保持一…

Bluetooth LE相关学习笔记

The Bluetooth LE Specifications The Bluetooth Core Specification 核心规范适用于 Bluetooth LE和Bluetooth Classic&#xff0c;它定义了蓝牙的体系结构及其层次&#xff0c;描述和定义了蓝牙的关键特性&#xff0c;定义了设备在协议栈的特定层上进行重要操作的方法和通信…

【圣诞限定】2022的末尾,送TA一颗圣诞树吧

2022年圣诞节&#xff0c;很高兴能遇见你。 一、前言 不知不觉又到年末啦&#xff0c;今年遇到了超级超级棒的人&#xff0c;希望能跟他一起做很多很多事&#xff0c;完成很多很多未完成的心愿。既然是圣诞节限定&#xff0c;那就送他一颗圣诞树吧&#x1f384;天天开心&#…

开发者百宝箱——DevToys

开发者百宝箱——DevToys 文章目录 简介安装转换类型编码/解码格式化生成器文本处理图片设置参考文献 简介 DevToys 是一个开发人员的工具箱&#xff0c;基于 UWP 开发&#xff0c;免费开源无广告&#xff0c;支持中文&#xff0c;功能有&#xff1a; 转换类型 JSON / YAML…

【C语言进阶】指针的进阶

在初级阶段的《指针》章节已经接触过了&#xff0c;我们知道了指针的概念&#xff1a; 1. 指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。 2. 指针的大小是固定的4/8个字节&#xff08;32位平台/64位平台&#xff09;。 3. 指针是有类型&#…

Word处理控件Aspose.Words功能演示:使用 C# 将 PowerPoint 演示文稿转换为 Word 文档

Aspose.Words 是一种高级Word文档处理API&#xff0c;用于执行各种文档管理和操作任务。API支持生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现和打印文档&#xff0c;而无需在跨平台应用程序中直接使用Microsoft Word。此外&#xff0c; Aspose API支持流行文件格式处…