MySQL进阶学习一(2024.10.07版)

2024-10-06


1.一条SQL语句是如何执行的

单进程的多线程模型

MySQL的物理目录

show global variables like "%basedir%";

InnoDB是如何存储表数据的

  • InnoDB其实是使用页为基本单位来管理存储空间的,默认的页大小为16KB。
  • 对于InnoDB存储引擎来说,每个索引都对应着一棵B+树,该B+树的每个节点都是一个数据页,数据页之间不必要是物理连续的,因为数据页之间有双向链表来维护着这些页的顺序
  • InnoDB的聚簇索引的叶子节点存储了完整的用户记录,也就是所谓的索引即数据,数据即索引

系统表空间(system tablespace)

系统表空间可以对应文件系统上一个或多个实际的文件,默认,InnoDB会在数据目录下创建一个名为ibdata
独立表空间(file-per-table tablespace)

在MySQL5.6.6以及之后的版本中,InnoDB默认为每一个表建立一个独立表空间,根据参数innodb_file_per_table控制

客户端与服务端的交互

数据库的核心在于存储引擎

MySQl逻辑架构

向MySQl发送一个请求---连接器

客户端如果长时间没有动静,连接器会将其断开,由wait_timeout控制,默认是8

长期使用长连接会导致内存飙升

向MySQl发送一个请求---查询缓存

将缓存放入一个引用表之中,通过哈希值进行引用

查询缓存时按需使用的,参数querycache type设置成DEMAND(默认不使用查询缓存)

虽然查询缓存有时可以提千系统性能,但也不得不因维护这块缓存而造成一些开销,比如每次都要去查询缓存中检索,查询请求处理完需要更新查询缓存,维护该查询缓存对应的内存区域。从MySQL 5.7.20开始,不推荐使用查询缓存,并在MySQL8.0中删除。

向MySQl发送一个请求---分析器

向MySQl发送一个请求---优化器

基于成本的查询优化器(Cost-Based Optimizer),IO和CPU

向MySQl发送一个请求---执行引擎

三个阶段的权限判断

各种不同的存储引擎向上边的MySQL服务器层提供统一的调用接口(也就是存储引擎API)包含了几十个底层函数,像"读取索引第一条内容"、"读取索引下一条内容"、"插入记录"等等。

存储引擎

从 MySQL5.5之后,默认的存储引擎是 InnoDB。InnoDB 是一个通用的存储引擎,除非有特殊需求,推荐使用InnoDB.

SHOW ENGINES;

InnoDB体系架构

简要架构

InnoDB整体也分为三层:(多线程模型)

  • 内存结构(In-Memory(1)Structure),这一层在MySQL服务进程内;
  • OS Cache,这一层属于内核态内存;
  • 磁盘结构(On-Disk)这一层在文件系统上;

多线程模型

  • Master Thread:刷新脏页到磁盘,保证数据一致性(10秒操作与1秒操作)
  • I0 Thread:大量使用异步处理写I0请求,包括4类I0 Thread
  • Purge Thread:回收已经使用并分配的undo页
  • Page Cleaner Thread:1.2.X版本以上引入脏页刷新,减轻master的工作,提高性能

管理单位

当我们想从表中获取某些记录时,1noDB存储引擎需要一条一条的把记录从磁盘上读出来么?

InnoDB采取的方式是:

  • 将数据划分为若干个页,以可作为磁盘和内存之间交互的基本单位
  • InnoDB中页的大小一般为16KB,也就是在一般情况下,一次最少从磁盘中读取16 KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中

InnoDB内存架构

InnoDB在内存中主要包括下面几个部分:缓冲池、Change缓冲区、自适应哈希索引、Log缓冲区

缓冲池

Page:为了高效读取,缓冲池划分为页结构组织

LRU:当需求添加新的page时,最近最少使用的page被清除,同时新页面被添加到链表的中间部分

这种中间点插入的策略,把链表分为两个子链表

头部:最近被访问过的"年轻"页

尾部:最近被访问的old page

这样使新子列表中保存更重要的page,旧子列表包含较少使用的这部分page

change buffer
  • Change Buffer是一种特殊的数据结构,当某些页面不在缓冲池中,缓存会改变二级索引page,这可能会造成insert,update,delete(DML)操作会与其他从缓冲池中的读操作加载的page合并。
  • 为了避免频繁的I0随机读写,当更新和删除操作时,并不会立即写入磁盘,而是会选择系统空闲时定期进行写入磁盘的操作。

落盘机制(redo、change buffer):

  • 定时 master thread 1s or 10s
  • 业务使用(提交或查询)
  • 缓存区达到阀值(1/2)
日志缓冲区

日志缓冲区是保存要写入磁盘上日志文件的数据的内存区域,即redo log buffer。

Write Ahead Log策略:当事务提交时,先写重做日志,然后再择时将脏页写入磁盘【随机写变为顺序写】

日志缓存区大小:由innodb log_buffer_size 变量定义,默认16M, 可以节省磁盘I/0

日志刷新频率:innodb flushlog_at_trx_commit控制如何写入日志缓冲区的内容并刷新到磁盘

行-页-段的过程

分析成本的考量

I/O成本:从磁盘到内存这个加载的过程损耗的时间称之为1/0成本

CPU成本:读取以及检测记录是否满足对应的搜索条件、对结果集进行排序等这些操作损耗的时间称之为CPU成本

页是磁盘和内存之间交互的基本单位,读取一个页面花费的成本默认是1.0,读取以及检测一条记录是否符合搜索条件的成本默认是0.2

步骤:

  1. 根据搜索条件,找出所有可能使用的索引
  2. 计算全表扫描的代价
  3. 计算使用不同索引执行查询的代价
  4. 对比各种执行方案的代价,找出成本最低的那一个

查询:

explain过程进行解释

2.MySQL事务隔离

  • 保证一组数据库操作,要么全部成功,要么全部失败的
  • 事务支持是在引擎层实现
  • MySQL是一个支持多引的系统,但并不是所有的弓擎都支持事务
  • 支持事务是InnoDB引擎的重要特性之一

隔离性

ACID的I:隔离性

(1)脏读(dirtyread):读取创了未提交的脏数据

(2)不可重复读(non-repeatable read):两次读取之间的数据被改变或消失

(3)幻读(phantom read):A事务在更新事务读取的同时B事务更新数据,就会惊奇的发现了这些新数据,貌似之前A读到的数据

隔离级别

(1)读未提交:一个事务还没提交时,它做的变更就能被别的其他他事务看到。

(2)读已提交:一个事务提交之后,它做的变更才会被其

(3)可重复读:一个事务执行过程中看到的数据 ,总是跟这个事务在启动时看到的数据是一致的。在可重复读隔离级别下,未提交变更对其他事务是不可见的。

(4)串行化:对于同一行记录,读或写都会加锁。当出现锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

读未提交: 2 2 2

读已提交:1 2 2

可重复读:1 1 2(事务A执行期间的数据是一样的)

串行化:1 1 2(事务B执行之后会更新锁住)

实现过程

  • 读未提交:直接返回记录上的最新值,没有视图概念。
  • 读已提交:在每个SOL语句开始执行的时候创建视图。
  • 可重复读:在事务启动时创建视图,整个事务存在期间都用这个视图。
  • 串行化:直接用加锁的方式来避免并行访问。

默认隔离级别参数

3.深入浅出索引

索引是什么东东?

索引是存储引擎用于快速查找记录的一种数据结构

七大查找算法

  • 顺序查找
  • 二分查找
  • 插值查找
  • 斐波那契查找
  • 树表查找
  • 分块查找
  • 哈希查找

索引数据结构

哈希表

适用于等值查询

有序数组

插入和修改成本高

B+树

为什么MySQL用B+树做索引而不用B-树或红黑树

原因:面试的时候背过

表中 R1~R5 的(ID,k)值分别为(100,1)、(200,2)、(300,3)、(500,5)和(600,6)

基于主键索引和普通索引的查询有什么区别?

主键索引:则只需要接叟索 ID 这棵 B+ 树

普通索引:要先搜索k索引树,得到ID内值为 500,再普通索引查询方式,则需要到 ID 索引树搜索一次。这个过程称为回表.

MyISAM索引实现

  • 叶节点的data域存放的是数据记录的地址
  • 主索引和辅助索引在结构上没有任何区别,只是主索引要求key是唯一的

InnoDB索引实现

InnoDB是进行行锁的,所以MyISAM不如使用InnoDB


2024.10.07

4.普通索引和唯一索引的选择

InnoDB体系结构

select id fromT where k=5

  • 条件的第一个记录(5,500)后,需要查找对于普通索引来说,查找到满下一个记录,直到碰到第一个满足 k=5 条件的记录。
  • 对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。

更新过程

  • 当需要更新一个数据页时,如果类据页在内存中就直接更新,
  • 而如果这个数据页不在内存中的讨舌,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个类据页的时候,将数据页读入内存,然后执行change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。

change buffer的使用场景

  • 对于唯一索引来说,所有的更新桑作都要先判断这个操作是否违反唯一性约束。比如,要插入(4,400)这个记录就要先判断现在表中是否已经存在 k=4 的记录,而这必须要将数据页读入内字才能判断。如果都已经读入到内存了,那直接更新内存会更快,就没必要使用change buffer 了。
  • 因此,唯一索引的更新就不能使,月change buffer,实际上也只有普通索引可以使用。

InnoDB插入数据的流程

第一种情况是,这个记录要更新的目标页在内存中。这时,InnoDB 的处理流程如下:

  • 对于唯一索引,找到3和5之间的位置, 判断到没有冲突,插入这个值,语句执行结束;
  • 对于普通索引,找到3和5之间的位置,插入这个值,语句执行结束.

第二种情况是,这个记录要更新的目标页不在内存中。这时,InnoDB 的处理流程如下:

  • 对于唯一索引,需要将数据页读入内存,判断到没有冲突,插入这个值!
  • 对于普通索引,则是将更新记录在 change buffer.

注意:在change buffer中有此行记录的情况下,再次更改,是增加一条还是原地修改?

增加一条

change buffer的使用场景

普通索引的所有场景,使用 change buffer 都可以起到加速作用吗 ?

  • 因为 merge 的时候是真正进行数据更新的时刻,而 change buffer 的主要目的就是将记录的变更动作缓存下来,所以在一个数据页做 merge 之前,changebuffer 记录的变更越多(也就是这个页面上要更新的次数越多),收益就越大。因此,对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 change buffer 的使用效果最好。这种业务模型常见的就是账单类、日志类的系统。
  • 反之,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件将更新先记录在 change buffer,但之后由于马上要访问这个数据页,会立即触发merge 过程。这样随机访问 10 的次数不会减少,反而增加了 change buffer 的维护代价。所以,对于这种业务模式来说,change buffer 反而起到了副作用。

change buffer与redo log在插入过程之中的使用

insert into t(id,k) values(id1,k),(id2,k2):

change buffer与redo log在读取过程之中的使用

select * from t where k in(k1, k2);

  • 读 Page1的时候,直接从内存返回。虽然磁盘上还是之前的数据,但是这里直接从内存返回结果,结果是正确的。
  • 然后应用 change要读 Page 2 的时候,需要把 Page 2 从磁盘读入内存中,buffer 里面的操作日志,生成一个正确的版本并返回结果。

redo log 主要节省的是随机写磁盘的 IO消耗(转成顺序写),而 change buffer主要节省的则是随机读磁盘的 IO 消耗。

5.MySQL词法分析

词法分析概念

词法分析(英语:lexicalanalysis)是计算机科学中将字符序列转换为单词(Token)序列的过程。进行词法分析的程序或者函数叫作词法分析器也叫扫描器(Scanner)。词法分析器(Lexicalanalyzer.简称Lexer)般以函数的形式存在,供语法分析器调用。

词法解析过程

首先是sql_chars.cc之中的进行状态机

select * from demo1;解析

初始化会获取输入流

接下来进入状态机之中

返回全部的字符串

接下来返回s,求取物理机的内容

进入循环扫描过程

语法解析匹配存在

上述内容对应sql_yacc.cc之中的语法解析部分 SELECT_SYM=748

匹配*

这里的*是匹配的ascll之中的*也就是42

from demo1过程是同上的.

from 对应452 寻找表的过程IDENT_QUDENT 484,还要在语法解析过程继续进行转换.

最终的一个字符串是\0,对应MY_LEX_EOL的状态机,然后在对应MY_LEX_END状态机,如下所示:

show table;解析

相关推荐
~kiss~3 分钟前
Rust学习~tokio简介
开发语言·学习·rust
莳花微语8 分钟前
使用MyCAT实现分布式MySQL双主架构
分布式·mysql·架构
he2581914 分钟前
centOS 7.9 安装JDK MYSQL
java·mysql·centos
夜泉_ly3 小时前
MySQL -安装与初识
数据库·mysql
qq_529835354 小时前
对计算机中缓存的理解和使用Redis作为缓存
数据库·redis·缓存
StickToForever5 小时前
第4章 信息系统架构(五)
经验分享·笔记·学习·职场和发展
月光水岸New6 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6756 小时前
数据库基础1
数据库
我爱松子鱼6 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo6 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库