Mysql 精通

文章详细介绍了MySQL的InnoDB存储引擎的工作原理,包括页的设计、缓冲池(Bufferpool)的管理、事务的特性、并发控制机制如MVCC以及不同隔离级别的概念。还讨论了如何处理删除、更新和插入操作,以及间隙锁在防止幻读中的作用。
摘要由CSDN通过智能技术生成

 

目录

如何设计一个page?如果没有索引肯定是全表扫描

如果要你来设计一个buffer pool怎么来设计?

mysql存储引擎原理、设计

数据页page(固定大小16k)

mysql innodb 存储引擎内存管理

事务

事务特性

并发

隔离级别

事务实现原理

mvcc :解决了脏读和不可重复读的问题,并发时不用加锁就可以达成读已提交和可以重复读的目的

undo log

redo log

innodb锁:锁都是加在主键上的

如果我们来设计间隙锁的规则?


我们有一条sql发送给mysql,mysql服务端对sql进行解析,缓存,再交由存储引擎取读写磁盘

前言:先把整个数据库详细的说一下

假设我们来设计一个数据库存储,可以把他想象成一个字典,每个词相当于我们的一行数据。

我们想查找数据,需要有目录,目录就是我们的索引,innodb提供了两种索引:一种是主键索引、另一种是非主键索引,这个后面会说。

我们要找一行数据,有索引的话,判断是否是主键索引

        步骤1:主键索引的话,B+树查找,查找到具体主键数据,这里很多人都没说明白,就贴张图-Data,这个data指的是地址,可以理解为哪个page页,和字典一样,然后在page内用二分法查找

        步骤2:非主键索引的话,B+树查找,找到主键,经过回表回到步骤1

如何设计一个page?如果没有索引肯定是全表扫描

        有个概念:page分配了一个固定大小为16k的磁盘空间,我们的一行数据存储在page里,没有紧挨着存储的,因为我们会删除,会插入,会更新,所需空间会变,所以我们是逻辑存储

        page 肯定要记录页号,双向链表记录前后页地址。

        想象一下:我们要想在字典的一页中找某个单词,是不是遍历查找

        那么这个遍历我们再优化一下,我们是不是维护一个数组slot来存储具体范围的数据,先根据这个数组做二分查找,判断具体是哪一区域,然后根据链表遍历

        注意: 由于在page里面,是逻辑存储,删除是逻辑删除,更新会在链表后面增加一个节点,原来占用的磁盘空间会被释放,所以表用久了,会有内存随便,和逻辑删除的无用数据

·       由于内存操作比磁盘操作要快,所以mysql引入了一个概念:缓冲区。就是说mysql启动之后,会在内存中开辟一个指定大小的内存空间 buffer pool

如果要你来设计一个buffer pool怎么来设计?

        1、加载一条数据时候,把整个page页加载到内存里,那么我们的内存就会有很多个page。buffer pool的存储的基本单元就是page。那么我们可以维护一个大小的空闲链表,提前将内存分区,有page直接找个内存地方存储

        2、维护一个映射关系:内存中的page地址和磁盘的page地址映射,方便写入,更新等操作直接找到内存中的page进行操作

        3、还需要维护一个非空闲链表:但是这个链表,要有淘汰策略LRU:冷热分区、固定时间冷-》热,指定次数更新热区,冷区规则:淘汰尾或刷脏页到磁盘

         4、当然有可能内存中的数据和磁盘里的数据不一致,还没有完成刷盘,我们就要维护一个脏页链表

mysql存储引擎原理、设计

数据页page(固定大小16k)

已分配内容

未分配内容

page维护策略:为了解决删除碎片问题:最好做定时收缩

顺序保证

插入策略

页内查询:跳表概念

mysql innodb 存储引擎内存管理

请求到内存里检索:一个一个page加载到内存里

页面淘汰:LRU -》 LFU(redis:按访问频次淘汰,增长因子和衰减因子) -》 

        避免热数据被淘汰:冷热分区LRU,冷数据固定时间迁移到热数据、热数据到冷数据

Buffer pool:

page:

freelist:空闲page链表

flush list:脏页链表

pagehash:内存page和磁盘page映射关系

LRU: 冷热lru如何实现的?

事务

事务特性

aid -》 c

原子性:事务要不全部成功,要不全部失败

隔离性:事务的隔离

持久性:事务提交,永久有效

一致性:aid已经保证了一致性

并发

脏读:读到未提交的数据

不可重复读:两次读取的不一样

幻读:虽然事务隔离了,但是看着没问题,但是执行不下去

隔离级别

读未提交 

读已提交:会造成 RC

可重复读:但会造成幻读问题 RR

串行读 加锁,性能很低,基本不用

事务实现原理

mvcc :解决了脏读和不可重复读的问题,并发时不用加锁就可以达成读已提交和可以重复读的目的

下面以RR为例

具体过程:维护了undo_log .  每次开启事务后,第一个未加锁的select 会产生一个read view记录。

        在查询的时候,会并发很多事情,有的人在你查询之前就把这条数据更新了,你是可以看到他更新的数据的。如果你查完,另一个人把这条数据更新了,你是不能知道这条数据的。如果你查的时候,另一个人想更新这条数据,还在填资料,你也是不能知道的。这三个场景是必要条件。

        所以mysql维护了一个不用加锁的机制:mvcc来解决这个问题。

当前读:一般遇不到。都是加锁才能叫当前读。 加共享锁(s/读锁)shaer in lock mode、排它锁(x/写锁)for update、间隙锁

快照读:产生一个reader view

reader view:维护的一个链表:活跃的事务列表

undo log

        用于回滚,mvcc用到的

redo log

        内存中存了redolog 刷盘到磁盘的redolog之后,内存中的redolog回收,磁盘的redolog写入磁盘中时,磁盘中的redolog回收

innodb锁:锁都是加在主键上的

类型

共享锁:读锁 lock in share mode

排它锁:写锁 for update 

锁力度:

行锁:

间隙锁

Next-Key Lock:行锁与间隙锁组合起来用就叫做Next-Key Lock。

表锁

注: update delete insert 都会自动加排它锁 for update ,是先select 再操作

间隙锁的作用:解决幻读,无法插入数据到数据间隙中。

注意间隙锁会造成死锁

如果我们来设计间隙锁的规则?

解决问题:满足我们条件的数据不能新增?

1、如果我们删除name=?的话,如果name不是索引,name是全局加锁

如果name有索引,根据name找到所有的主键,在每个主键的前后(根据链表可以找到)增加间隙锁

2、如果我们删除age > ?的话,同 1

3、如果我们删除id > 4 , 间隙锁加在(4,无穷大)或(4, 下一个主键id)

        

             

        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值