InnoDB存储引擎【MySQL从放弃到入门】

文章目录

  • InnoDB存储引擎【MySQL从放弃到入门】
    • 1.逻辑架构
      • [1.1 一条SQL语句是怎么执行的呢?](#1.1 一条SQL语句是怎么执行的呢?)
      • [1.2 MySQL存储引擎有哪些?](#1.2 MySQL存储引擎有哪些?)
    • 2.MySQL一行记录是怎么存储的?
      • [2.1 NULL值是如何存储的?](#2.1 NULL值是如何存储的?)
    • 3.char和varchar的区别?
    • 4.数据页
    • [4.1 聚簇索引和非聚簇索引](#4.1 聚簇索引和非聚簇索引)
    • [4.2 Buffer Pool](#4.2 Buffer Pool)
      • [4.2.1 什么是Buffer Pool?](#4.2.1 什么是Buffer Pool?)
        • [4.2.2 空闲页?](#4.2.2 空闲页?)
        • [4.2.3 脏页?](#4.2.3 脏页?)
        • [4.2.4 缓存命中率咋样?脏页更新到磁盘时机呢?](#4.2.4 缓存命中率咋样?脏页更新到磁盘时机呢?)
        • [4.2.5 Buffer Pool可以代替Redis吗?](#4.2.5 Buffer Pool可以代替Redis吗?)
    • [4.3 Change Buffer](#4.3 Change Buffer)

InnoDB存储引擎【MySQL从放弃到入门】

1.逻辑架构

1.1 一条SQL语句是怎么执行的呢?

首先,MySQL的连接器会负责建立连接、校验用户身份、接收客户端的SQL语句;之后MySQL会在查询缓存中查找数据,但是在8.0版本移除了;其次MySQL的解析器会对SQL语句进行词法分析和语法分析,然后构建语法树,方便后续模块读取表名、字段、语句类型;然后MySQL的优化器会基于查询成本的考虑,判断每个索引的执行成本,从中选择成本最小的执行计划;最后MySQL的执行器执行查询语句,从存储引擎读取记录,返回个客户端。

1.2 MySQL存储引擎有哪些?

我所了解的存储引擎有InnoDB、MyIsam、Memory。

(ps:那你知道MyIsam和InnoDB有什么区别吗?)

InnoDB在数据存储方面采用的是索引组织表,表数据和索引数据都存到同一个文件中(.frm&.ibd)。MyIsam采用的是堆表,数据和索引分开存储,因此表数据和索引数据会分开放在两个不同的文件中存储。

InnoDB引擎B+树叶子节点存储的是索引和数据,但是MyIsam存储的是索引和数据地址。另外,InnoDB支持行级锁和事务,但是MyIsam都不支持,只支持表级锁。

2.MySQL一行记录是怎么存储的?

表空间由段、区、页、行组成。

2.1 NULL值是如何存储的?

MySQL存储一行数据的时候,会使用上面这个格式进行存储,其中NULL值列表就是用来保存NULL值的。

MySQL行格式中会用NULL值列表来标记值为NULL的列,每个列对应一个二进制位,如果列的值为NULL,就标记这个位为1,否则为0,所以NULL值不会存储在行格式中的真实数据部分。

NULL列表最少会占用1字节空间,当表中所有列都定义为NOT NULL时,行格式中就不再需要NULL值列表,可以节省1字节空间。

总结,为什么说使用NULL值列表了,就可以节省空间?

就比如,一个字段varchar(200),但是是NULL,如果你不用标记位1来表示它为空,那么会给它分配最多200字节的空间,如果使用NULL列表,只需要1bit就可以表示它是NULL了,就不需要分配这个空间。

3.char和varchar的区别?

假如说一个字段是varchar(10),但它其实只有6个字节,那他内存中占的存储空间是多少?在文件中占的存储空间是多少?

答:内存会占用10字节,文件存储占6字节,并且额外用1-2字节存储可变长字符串长度的空间。(保存达到文件的时候,只会存储实际使用的字符串大小,但是内存会按varchar最大值固定分配大小。)

char是固定长度的字符串类型,它在系统中占用固定的存储空间,如果实际存储的字符串小于定义的长度,系统会自动用空格填充。

varchar是可变长的字符串类型,实际存储只占用实际字符串长度的空间,不会进行空格填充。

4.数据页

4.1 聚簇索引和非聚簇索引

聚簇索引和非聚簇索引的B+树有什么区别?

聚簇索引和非聚簇索引最主要的区别就是B+树叶子节点存放的内容不同:

  • 聚簇索引的B+树的叶子节点存放的是主键值和完整的记录;
  • 非聚簇索引的B+树叶子节点存放的是索引值和主键值。

如果查询条件用到了二级索引,但是查询的数据不是主键值,也不是二级索引值,这时在二级索引找到主键值后,就需要回表才能查找到数据,需要扫描两次B+树。如果查询的是主键值,因为在二级索引就能查询到,但时候就会用到覆盖索引,不需要回表,只需要扫描一次B+树。

4.2 Buffer Pool

InnoDB对LRU做了哪些优化?

4.2.1 什么是Buffer Pool?

Buffer Pool就是MySQL为了提高查询性能的一个缓冲池,位于存储引擎层。默认innodb_buffer_pool_size=128MB。

InnoDB会为Buffer Pool申请一片连续的内存空间,然后按照默认的16kb的大小划分出一个个页,Buffer Pool中的页叫做缓存页。

为了管理这些缓存页,InnoDB为每一个缓存都创建了一个控制块,这些控制块包括【缓存页的表空间、页号、缓存页地址、链表节点】等。

4.2.2 空闲页?

Buffer Pool是一片连续的内存空间,但是在MySQL运行一段时间后,肯定有空闲的也有被使用的。那么这些空闲页怎么办?

我们下次读取磁盘数据的时候,是要遍历Buffer Pool找到一个空闲页吗?那也太浪费的吧。所以就为这些空闲页创建一个Free链表。

那么每当需要加载数据的时候,直接在Free链表拿一个就行。

4.2.3 脏页?

如果说我的缓存页被修改了,那么就直接更新我的磁盘吗?那也太拉低性能了吧。所以就设计了脏页,由后台线程去更新到磁盘好了。

那么怎么找这个脏页呢?那就创建一个链表吧,就叫Flush链表。

4.2.4 缓存命中率咋样?脏页更新到磁盘时机呢?

对于这个Buffer Pool来讲,我们当然希望访问次数多的一直留下,访问次数少的就给他移除。

那么就使用LRU算法 ,来实现这个功能,具体LRU是什么呢,可以看这篇文章。
https://blog.csdn.net/m0_73337964/article/details/144726361?spm=1001.2014.3001.5501

如果直接使用LRU算法的话,会出现两种问题预读失效和Buffer Pool污染。

1.预读失效

预读失效就是MySQL在访问数据时,会顺带给邻居也读出来,但是这些被提前读出来的邻居,并没有被访问,相当于这个预读白做了,这就是预读失效。

要避免预读失效带来的影响,最好就是让预读的页停留在Buffer Pool里的时间尽可能短,让真正被访问的页移动到LRU链表头部,从而保证真正的热数据留在Buffer Pool里的时间尽可能长。

MySQL将LRU链表分为了两个部分young和old区域。

预读的页加载到old区域头部,当页真正被访问时,才将其加入到young区域头部。

2.Buffer Pool污染

当某一个SQL语句,在Buffer Pool比较有限的情况下,可能会将Buffer Pool里的所有页都替换出去,导致大量热数据被淘汰了,等这些热数据又被再次访问的时候,由于缓存未命中,就会产生大量的IO,这就是Buffer Pool污染。

MySQL的解决方案是,进入到young区域条件增加了一个停留在old区域的时间判断。

  • 如果后续的访问时间与第一次访问的时间在某个时间间隔内,那么该缓存页就不会被从old区域移动到young区域的头部。
  • 如果后续的访问时间与第一次访问的时间不再某个时间间隔内,那么该缓存页移动到young区域的头部。
    间隔时间默认为innodb_old_blocks_time=1000ms,也就是说只有同时满足被访问与在old区域停留时间超过1秒两个条件,才会被插入到young区域头部。
3.脏页更新时机
  1. 当redo log日志满了的情况下,会主动触发脏页刷新到磁盘;
  2. Buffer Pool空间不足时,需要将一部分数据页淘汰掉,如果淘汰的是脏页,就先将脏页同步到磁盘;
  3. 空闲时,后台线程定期将适量的脏页刷入到磁盘;
  4. 关闭前,把所有脏页刷入到磁盘。
4.2.5 Buffer Pool可以代替Redis吗?

我觉得不能代替。

4.3 Change Buffer

推荐链接:09 普通索引和唯一索引,应该怎么选择?

原文章来自:揭开 Buffer Pool 的面纱

以上是我的阅读总结。

相关推荐
白鲸开源1 小时前
(二)从分层架构到数据湖仓架构:数据仓库分层下的技术架构与举例
大数据·数据库·数据分析
阿维的博客日记1 小时前
从夯到拉的Redis和MySQL双写一致性解决方案排名
redis·分布式·mysql
好玩的Matlab(NCEPU)1 小时前
Redis vs RabbitMQ 对比总结
数据库·redis·rabbitmq
21号 11 小时前
16.MySQL 服务器配置与管理
服务器·数据库·mysql
我的offer在哪里1 小时前
MongoDB
数据库·mongodb
SamDeepThinking2 小时前
为超过10亿条记录的订单表新增字段
mysql
练习时长一年3 小时前
AI开发结构化输出
数据库
IvorySQL3 小时前
灾难恢复工具内核细节探究与分享
数据库·postgresql·开源
lypzcgf3 小时前
商城小程序数据库表结构文档
数据库·小程序·电商
jjw_zyfx4 小时前
Ubuntu上vue3 vite使用MBTiles搭建地图服务器
服务器·数据库·ubuntu