Mysql架构体系学习笔记(day1)—Mysql原理篇

Mysql存储引擎原理拆解

mysql的数据存储在Page里,填满了就会分配一个新的Page,Page是存储空间分配的基本单元

每个Page的大小为16K

页头—记录页面的控制信息,共占用56字节,包括Page的左右兄弟Page指针,Page空间使用情况等。(有左右兄弟Page指针,说明mysql中Page之间为双向链表)

最小最大虚记录—确定数据范围,最大虚记录比Page内部最大主键要大,最小虚记录比Page内部最小主键要小。

记录堆—每次新插入时会在记录堆新增一条数据,分为有效记录与已删除记录两种。

已删除记录—已删除记录组成的链表,会形成自由空间链表,这与mysql的插入策略有关。

未分配空间—Page没装满时会出现未分配空间

slot区—以虚记录为区间平均分隔,每个slot区都是一个链表,以此来增强查询的效率

页尾—Page最后部分,占8个字节,主要存储Page校验信息

页内记录维护使用逻辑有序方式

不使用物理有序的原因因为由于记录大小不等,无法使用二叉树查询。所以使用逻辑有序,通过slot区进行查询优化

数据库收缩

主库,从库进行替换,将数据库重新压缩

InnoDB内存管理

存储引擎需要在内存中查询

预分配内存空间

数据加载单元为Page单元

页面管理

空闲页—没有数据的Page

数据页—有数据的Page

脏页—有数据但是修改了的Page(与磁盘数据不一致,需要生效的Page)

页面淘汰

LRU算法—当我们做数据收缩之后,内存是空的,需要进行数据预热,将访问频繁的数据加载到内存中。由于Mysql中Page结构为slot区样式链表,我们将访问频繁的数据作为表头加载进内存;访问新Page的啥时候,删除链表最后一位的Page,将新Page加入表头。(按时间排序,大量数据全表扫描容易造成缓存区污染—无法保留热数据)

LFU算法 —(按访问频率进行淘汰) 例如Redis

Mysql内存管理

Buffer Pool — 预分配的内存池

Page — Buffer Pool 的最小单位

Free List — 空闲Page组成的链表(先找空闲页)

Flush list — 脏页链表 (提交后将脏页刷盘)

Page hash — 维护内存Page和文件Page的映射关系(由于内存Page为动态的,哪有地方放哪里,所以需要维护)

LRU — 内存淘汰算法

mysql的LRU策略

简单的LRU策略会出现当大量数据被扫描时,热数据被污染替换,但mysql为什么采取LRU策略?

mysql中有热数据区与冷数据区

 这时候就需要一种策略来确定什么样的冷数据会被加载到热数据区,mysql是这样确定的,当冷数据区的数据存在超过指定时间(innodb_old_ blocks_time)后,当下一次被请求访问的时候就会被加载到热数据的Head。

midpoint指向5/8的位置,只要向左移动一位,就实现了热数据区数据向冷数据去的迁移。

LRU_new中数据如何进入Head,mysql认为每次访问都将数据放入Head提升不高(Head数据查询最快)所以采用 (访问数据当时的全局淘汰Page数 - 访问的数据上次成为Head时的全局淘汰Page数)> LRU_new长度的1/4   则将被访问的数据放置到Head

MVCC

多版本并发控制 — 解决读写冲突,有了MVCC读就不用加锁了,使用隐藏列实现 每一行数据都有一个事务ID,相当于版本号;还有一个地址,指向上一个版本。就可以做到可重复读

mysql中count(*)慢,是因为基于MVCC快照读,没办法使用计数器,只能一条条数。

快照读 — 创建快照的这一刻未提交的事务及之后创建的事务全都不可读

策略为:查询时拿到事务id,创建一个未提交的事务活跃列表,判断查询的事务id是否小于活跃列表最小id,再判断事务id是否大于活跃列表最大id,最后判断事务id是否在活跃列表中

 undo log — 用于回滚日志,保证事务原子性,实现数据多版本

由于undo log 不仅用于回滚,还需要实现数据多版本,所以不能随便删除。需要根据系统活跃的最小活跃事务ID Read View 将之前的undo log进行删除

redo log — 用于记录修改,异常恢复,循环写文件

redo log 意义:体积小,先记录Page的修改,然后顺序记录日志后进行刷盘

写入流程:innodb接收修改命令 -> 记录undo log -> 更新内存数据 -> 记录prepare -> 更新完成返回 -> 提交命令 -> 记录进行commit -> 写入磁盘

innodb锁

锁作用在索引上        

如果加锁的话需要判断两种情况

唯一索引/非唯一索引        RC隔离级别/RR隔离级别

RR隔离需要用到间隙锁(GAP锁),因为可能在写锁的过程中加入了新的数据

加锁过程 :索引上锁 -> 回表给主键上锁 -> 锁住数据

避免锁表

1.某个字段没有建索引,用它进行where查询,没有对应的索引树(B+树),这是全表扫描,就要锁表。

2.某个字段建立索引,但是索引失效(比如%号放左边),这时候也会全表扫描,锁表。

3.某个字段建立索引,索引不失效,但是where查询条件的值表中没有,这时候依旧会走这个索引的B+树,到叶子节点时候,发现没有该数据,返回结果空,这不是全表扫描,不会锁表。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值