MySQL-innodb
2021-05-27 16:26:54 10 举报
MySQL的innodb存储引擎
作者其他创作
大纲/内容
在 MySQL 事务中, 锁的实现与隔离级别有关系, 在 RR(Repeatable Read) 隔离级别下, MySQL 为了解决幻读的问题, 以牺牲并⾏度为代价, 通过 Gap 锁来防⽌数据的写⼊, ⽽这种锁, 因为其并⾏度不够, 冲突很多, 经常会引起死锁。 现在流⾏的 Row 模式可以避免很多冲突甚⾄死锁问题, 所以推荐默认使⽤ Row +RC(Read Committed) 模式的隔离级别, 可以很⼤程度上提⾼数据库的读写并⾏度。
是不可见
幻读(读取到别的事务未提交的新数据)
表级锁
DB_Row_Id
各种存储引擎
3.InnoDB存储架构
update ... (更新操作)delete ... (删除操作)insert ... (插入操作)select ... lock in share mode (共享读锁)select ... for update (写锁)
CAP+RRRow+RC
隔离级别
Record_TRX_ID在活跃列表
对于非聚集索引的插入或者更新操作:1.先判断插入的非聚集索引页是否在缓冲池中,2.如果在,则直接插入,3.如果不在,则先放入一个insert buffer中,然后再以一定的频率进行Insert buffer和辅助索引叶子节点合并操作。目的:这种时候,经常能将多条记录的插入合并到一个操作中,这样就大大提高了非聚集索引离散插入的性能。条件:非聚簇索引,非唯一索引
I(隔离性)
判断索引是否在buffer Pool
否
当前事务ID
只解决了当前读幻读问题
只能被一个事务获得,允许获得锁的事务修改数据
4.serlize
⽤户表空间:是指以 .ibd 为后缀的⽂件, ⽂件中包含 insert buffer 的 bitmap 页、 叶⼦页(这⾥存储真正的⽤户数据) 、 ⾮叶⼦页。 InnoDB 表是索引组织表, 采⽤ B+ 树组织存储, 数据都存储在叶⼦节点中, 分⽀节点(即⾮叶⼦页) 存储索引分⽀查找的数据值。
read_thread线程
executor
读数据
为什么不能是唯一索引? 之所以不支持唯一索引,是因为如果辅助索引是唯一索引,那么在插入时需要校验唯一性,校验唯一性的时候就会发生离散读取,从而又增加了开销,那么insert buffer得不偿失。
删除基于最小活跃事务ID
更新非唯一二级索引时,先将数据写入 buffer
回滚指针找到上个版本
1.redolog 刷盘机制可以进行设置,通过innodb_flush_log_at_trx_commit参数进行设置,默认是1
MVCC:即多版本并发控制。当innoDB存储引擎通过MVCC多版本控制的方式来读取当前执行时间数据库中的行数据,如果读取的行正在执行delete或者update操作,这时读取操作不会因此等待行上锁的释放;相反,innoDB会去读取行的一个快照数据(undo log),从历史快照(undo log链)中获取旧版本数据来保证数据一致性。由于历史版本数据存放在undo log页当中,对数据修改所加的锁对于undo页没有影响,因此不会影响用户对历史数据的读,从而达到非一致性锁定读,提高并发性能。
内存
共享表空间
DB_TRX_Id当前事务ID
2.read commit
1.master线程:主循环(loop) 、 后台循环(background loop) 、 刷新循环(flush loop) 、 暂停循环(suspend loop) 。 Master Thread 会根据其内部运⾏的相关状态在各循环间进⾏切换
4. 写日志
system tablespace
原子性
7.写入binglog文件与位置
main线程刷脏页到磁盘
1.管理连接,权限验证等mysql5.6之前采用BIO,1.规范,2.数据库连接数量有限切单socket连接读写频繁。优化:连接池数量不是越多越好,设置为(2*CPU数+磁盘个数即可)mysql 5.7以后变成了Pool-Threads 模式,使用EPOLL,实现高并发连接
myisam
Optimizer1.⽣成执⾏计划, 并选择合适的索引, 2.按照执⾏计划执⾏SQL 语⾔并与各个存储引擎交互。
DML
整个流程:①通过客户端/服务器通信协议与 MySQL 建⽴连接。②查询缓存, 这是 MySQL 的⼀个可优化查询的地⽅, 如果开启了 Query Cache 且在查询缓存过程中查询到完全相同的 SQL 语句, 则将查询结果直接返回给客户端; 如果没有开启Query Cache 或者没有查询到完全相同的 SQL 语句则会由解析器进⾏语法语义解析, 并⽣成解析树。③预处理器⽣成新的解析树。④查询优化器⽣成执⾏计划。⑤查询执⾏引擎执⾏ SQL 语句, 此时查询执⾏引擎会根据 SQL 语句中表的存储引擎类型, 以及对应的API 接⼜与底层存储引擎缓存或者物理⽂件的交互情况, 得到查询结果, 由MySQL Server 过滤后将查询结果缓存并返回给客户端。 若开启了 Query Cache, 这时也会将SQL 语句和结果完整地保存到 Query Cache 中, 以后若有相同的 SQL 语句执⾏则直接返回结果。
double write段
排他锁(X)写锁
undolog:回滚日志文件。当事务进行回滚时,需要依赖undo日志进行回滚操作。undo log存放在ibdata1共享表空间中,可以通过innodb_undo_directory参数指定单独存undo表空间的目录。在并发写入型负载中,我们可以把undo文件部署到单独的高速存储设备上
设置为 2
4.可串⾏化单版本的状态, 因为它所有的实现都是通过锁来实现的。
1.约束一致性2.数据一致性
3.可重复读在同一事物中,读取一条数据,不会出现数据不一致,解决了不可重复读。在mysql中使用MVCC实现,每次读的read view 都是第一次读取的版本,读取的数据就会一致。但是会出现幻读的情况,幻读是查询多条数据的时候,另一个事务新增数据后,会出现新增的数据。
rollback 段
MySQL提供一个sync_binlog参数来控制数据库的binlog刷到磁盘上去。默认,sync_binlog=0,表示MySQL不控制binlog的刷新,由文件系统控制它的缓存的刷新。性能是最好的,但是风险也是最大的。因为一旦系统Crash,在binlog_cache中的所有binlog信息都会被丢失。如果sync_binlog>0,表示每sync_binlog次事务提交,MySQL调用文件系统的刷新操作将缓存刷下去。最安全的就是sync_binlog=1,表示每次事务提交,MySQL都会把binlog刷下去,是最安全但是性能损耗最大的设置。这样的话,在数据库所在的主机操作系统损坏或者突然掉电的情况下,系统才有可能丢失1个事务的数据。但是binlog虽然是顺序IO,但是设置sync_binlog=1,多个事务同时提交,同样很大的影响MySQL和IO性能。对于高并发事务的系统来说,“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多。所以很多MySQL DBA设置的sync_binlog并不是最安全的1,而是100或者是0。这样牺牲一定的一致性,可以获得更高的并发和性能。
设置为 0
redo log buffer
redolog:重做日志文件。用于记录InnoDB引擎下事务的日志,他记录每页更改的物理情况。将对页面的修改操作写入到这个专门的文件中,并在数据库启动时从此文件进行恢复操作。
叶⼦页
A(原子性)
回滚对应undo位置
3.page_cleaner_thread:负责将 buffer pool 中的脏页刷新到磁盘
redo log
表行数据增加2字段
设置为 1
不可重复读(二次读取结果不同)
写数据
对查询语法进行分析
client connectors(JDBC/.NET等)负责处理客户端的连接请求, 与客户端创建连接
执行引擎
可见性判断创建快照这一刻,已经提交的事务才能看到不然根据Read View里面3个属性判断是否可读等
undolog日志文件
数据完整性
5.准备提交事务,redoLog日志刷盘
5.数据写到 data write buffer此步骤为顺序写
redo log 1
optimizer
commit
binlog日志文件
当设置为1的时候:事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。当设置为0的时候:事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,最多会丢失1秒钟的数据。当设置为2的时候:每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。设置为0和2可以大幅度提升插入性能,但是在故障的时候可能会丢失1秒钟数据,这1秒钟很可能有大量的数据,所以默认值和一般企业这里的值都设置的是1.
RedoUndo
Record_TRX_ID>最大ID
memery
事务特性
5.redo_log_thread负责把⽇志缓冲中的内容刷新到 Redo log ⽂件中
间隙锁
data page数据页
1.读未提交会发生脏读
在数据写入并落盘过程中产生了几个问题:1.insert Buffer page 加快写入速度。2.dubbo write 确保数据落盘准确。3.redolog落盘方式可选,redolog落盘方式与binglog落盘方式搭配,保证数据不丢失设置。
hash index自适应hash索引
分隔
磁盘
user tablespace
执行器
2.变更数据
客户端
lock info锁信息
4.写redoLog日志
MVCC
index 段
Service & utilities管理服务&⼯具集, 包括备份恢复、 安全管理、 集群管理服务和⼯具
write_thread线程4个线程
持久性
2.读已提交在同一事务中,读取一条数据,会出现不一样的结果,出现不可重复读在mysql中使用MVCC实现,此隔离级别,每次都会读最新的可用的read view,导致不同时刻数据不一致
是
MySQL 是通过 WAL(Write Ahead Log) 技术来实现原子性
main线程
Parser
redo logbuffer
binlog
锁粒度
redo log 2
可被多个事务获取,但阻止事务对行数据修改
数据文件
LRU 链表(最少活跃淘汰)
Redo buffer ⾥存储数据修改所产⽣的 Redo log
1.读取数据
隔离性
每次事务提交都会写入OS buffer,并调用fsync()刷盘
是:不可见
6.准备提交事务,binlog日志写入磁盘
undo段
QUERY CACHE
错误日志
SQL interface接收客户端发送的各种 SQL 语句, ⽐如 DML、 DDL 和存储过程等
data dictionary(页与数据的元数据)
cache全局缓存innodb Buffer Pool
....
insert buffer 段
当前读
2.read_thread 处理⽤户的读请求, 并负责将数据页从磁盘上读取出来, 可以通过参数设置线程数量。
每秒调用fsync()刷盘
每次提交都仅写入到os buffer
解决可重复度模式下的幻读问题锁的是两次当前读之前的GAP
redo_log_thread线程
undo
行锁
幻读指的就是你一个事务用一样的SQL多次查询,结果每次查询都会发现查到了一些之前没看到过的数据
一致性
insert Buffer cache
.....
Buffer POOL
*.IDB
数据落盘
非⼦页
innodb
index page索引页
insert_buffer_thread线程
锁的类型(都是作用在索引上)聚簇索引&二级索引
1.要么修改,要么没改
binlog:二进制日志文件,不管使用的是哪一种存储引擎,都会产生binlog。binlog都是基于SQL语句级别的。应用这种格式进行数据恢复时如果SQL带有rand或者uui等等函数可能导致与原数据不一致。binlog format有statement和row两个可选参数,row是记录的行的更改情况,可以避免数据不一致的问题。
3.repeated read
Connection Poll连接管理、用户身份认证与鉴权
2. InnoDB 架构
innodb存储引擎
4. write_thread 负责将数据页从缓冲区写⼊磁盘, 也可以通过参数设置线程数量, page_cleaner线程发起刷脏页操作后 write_thread 就开始⼯作了。
3. log日志
MVCC读取流程
page_cleaner_thread线程
共享锁(S)读锁
Buffer Pool
insert buffer 的 bitmap 页、
DB_ROLL_PTR回滚ID
加入MVCC后为啥还不能重复读关键点在于每次查询都生成新的ReadView所导致的
1.磁盘文件
可重复读(默认隔离级别)RR(repeat read)隔离可能幻读
4.MYSQL数据写入过程
flush 链表(刷脏叶)
.ibd文件
Mysql执行器
CONNECTOR
1.mysql 架构
操作引擎,返回结果
脏数据
1.加载数据缓存到
1.redolog + binlog
可见
MYSQL锁的实现
锁类型
每秒写入os buffer并调用fsync()刷盘
6.将double write buffer写入各表空间文件,这时是离散写入
mysql 事务与锁
redo/undo log
Os Buffer
InnoDB select count(*) from table 为什么慢
快照读
串行化(一般不用)性能太差
InnoDB 的Page Size一般是16KB,其数据校验也是针对这16KB来计算的,将数据写入到磁盘是以Page为单位进行操作的。而计算机硬件和操作系统,在极端情况下(比如断电)往往并不能保证这一操作的原子性,16K的数据,写入4K 时,发生了系统断电/os crash ,只有一部分写是成功的,这种情况下就是 partial page write 问题。MySQL 可以根据redolog 进行恢复,而mysql在恢复的过程中是检查page的checksum,checksum就是pgae的最后事务号,发生partial page write 问题时,page已经损坏,找不到该page中的事务号,就无法恢复。
1.由于innodb不支持hash索引,但是在某些情况下hash索引的效率很高,于是出现了 adaptive hash index功能,innodb存储引擎会监控对表上索引的查找,如果观察到建立hash索引可以提高性能的时候,则自动建立hash索引。
Buffer Pool
double write buffer 是 double write 所需的 buffer, 主要解决由于宕机引起的物理写⼊操作中断, 数据页不完整的问题。
Archive
数据⼀致性: 是⼀个综合性的规定, 或者说是⼀个把握全局的规定。 因为它是由原⼦性、 持久性、 隔离性共同保证的结果, ⽽不是单单依赖于某⼀种技术
8. 脏页数据刷盘
并发问题
data page dirty
redo Log buffer
生成执行计划、索引选择
全日志等.
2.写undolog日志便于事务回滚
D(持久性)
Parser对 SQL 语句进⾏语法解析⽣成解析树
1.唯一索引2.外键约束
默认不开启,8版本以后删除了,建议缓存用本地缓存或者redis等。
insert Buffer page
innodb三大特性之一:dubbo write
IO线程
所有需要全部加载到内存
物理磁盘
ibdata文件
事务的四大特性:ACID1.原子性2.持久性3.隔离性4.一致性
data page clean
redo log日志文件
脏读(读取未提交的数据)
1.read uncommit
C(一致性)
dubbo write
数据字典段
读已提交Read Committed不能重复度
redo log 3
物理文件系统
慢查询日志
mysql service层
读取未提交Read uncommitted存在脏读
WAL
memory
基于Undolog
sync_binlog
3.更新内存数据
Record_TRX_ID<最小ID
7.数据恢复时
使用了MVCC无法计数数量
索引文件
Read View机制活跃事务列表列表中最小事务ID列表最大事务ID你的事务ID:
1.事务
收藏
0 条评论
回复 删除
下一页