InndoDb逻辑存储结构及内存&磁盘结构
InnoDB数据字典由内部系统表组成,其中包含用于跟踪对象(如表,索引和表列)的元数据。元数据实际位于InnoDB系统表空间中。由于历史原因,数据字典元数据在某种程度上与InnoDB表元数据文件(.frm文件)中存储的信息重叠。
逻辑存储结构结构
表空间及文件
- 表结构定义文件.frm,是Mysql数据库本身的文件,和存储引擎无关。
- 表空间文件.ibd。
系统表空间
存储了doublewrite buffer, the change buffer, and undo logs.
当然,也可以指定将表的信息创建到这个表空间内。
每个表一个表空间
默认会使用innodb_file_per_table,存放的只是数据,索引,插入缓存和Bitmap页,入下图所示。
![](media/15204962282268/
优点:
1。 新增或删除一个表时,可以更加放标的处理磁盘空间。如果表数据存储在系统表空间中,那删除一个表后留下的空余磁盘空间,只能用来存储Innodb表数据。
2. 清空一个表 TRUNCATE TABLE 的数据更快,OPTIMIZE TABLE 压缩一个表清空不用的空间更方便。
3. 可以将不同的表放在不同的存储设备上,方便空间管理或备份恢复等操作,方便移动或删除一个表。
4. 当 innodb_flush_method 指定为O_DIRECT时,大多数Linux文件系统不支持单个文件并发写,所以每个表一个文件可能可以提高性能。
5. 提供空间扩展性,单个文件在很多方面受到限制。
潜在的缺点:
1.如果表太多,可能会浪费磁盘空间,每个表空间都有无用的空间。
2.导致更多的IO操作,无法把多个表的写入操作合并为一个fsync操作。
3.表太多,文件描述符很多,可能会影响性能。
undo 表空间
undo日志会存在共享表空间中,也可以存放在undo表空间。undo log的IO模式是的undo表空间存放在固态硬盘SSD里,然后共享表空间还是存放在机械硬盘里。
段、区、页、行
段:数据段、索引段、回滚段等。
区:由连续页组成的空间,在人和情况下每个区大小为1MB,InnodDb页大小为16KB,一个区有64个连续的页。
页、页是InnoDb磁盘管理的最小单位,根据索引查询到的是页,缓存中的也是页,然后在页中进行排序查找到要查询的行。
常见页类型有:
- 数据页(B-tree Node)
- u:do 页 (undo Log page)
- 系统页
- 事务数据页
- 插入缓冲位图页(Insert Buffer Bitmap)
- 大对象页。
行:很多个行构成一个页。
行记录格式:
REDUNDANT格式:
- 6字节,头部,用来标记记录是否删除以及下一条记录的相对位置等信息。The header is used to link together consecutive(连续的) records, and for row-level locking.
- 在聚簇索引中,有6字节的事务ID,和7字节的指向undo log的回滚指针。
- 如果没有指定主键,则会生成6字节的行id。
- 对于辅助索引,如果没有主键的话则会记录主键的列。
- 指向各字段的指针。
- 字段大于等于768字节的,会存到off-page里去,如果utf8mb4格式,char占大于3个字节,CHAR(255) 就会大于768.
COMPACT格式:
1.5个字节的header,用来标记记录是否删除以及下一条记录的相对位置等信息。The header is used to link together consecutive(连续的) records, and for row-level locking.
2.null标志位,表示了该行数据是否有null值。
3.在聚簇索引中,有6字节的事务ID,和7字节的指向undo log的回滚指针。
4.CHAR(N)保留最少N个字节,CHAR(N)列占用最大字符字节长度×N.N是指字符长度,不是字节长度。
DYNAMIC格式:
- TEXT和BLOG小于等于768字节会存在行里,否则会存在off-page,就是Uncompressed BLOB page。当行太长时,会把大于40字节的存到off-page。
索引
索引结构
B树:
B-树的特性:
1.关键字集合分布在整颗树中;
2.任何一个关键字出现且只出现在一个结点中;
3.搜索有可能在非叶子结点结束;
4.其搜索性能等价于在关键字全集内做一次二分查找;
优势:
树的层级低,进行IO的次数少。
B+树
B+树特性:
- 数据存在叶子节点。
- 叶子节点之间由链表相连。
B+树做为磁盘索引的优势:
1.磁盘读写代价更低。相比B-树,非叶子节点仅存储关键字,更小,查询时读取的磁盘块更少。
2. 有双向链表,遍历数据更块。在数据库中基于范围的查询相对频繁,所以此时B+树优于B树。
3. 查询效率稳定,每次查询数据都要达到叶子节点,IO次数相近。
聚集索引索引primary key
叶子节点存储了数据。聚集索引的存储是逻辑是连续的,并不要求是物理上连续的。
非聚族索引secondary key
没有存储数据,只存储了到聚集索引的指针。
磁盘结构
Doublewrite Buffer 两次写
- 读取数据到Buffer Pool。
- 修改数据,页变成脏页。
- 写入日志缓冲。
- 写redo log。
- 写Doublewrite Buffer.
- 写数据到磁盘。
两次写主要解决的是向磁盘文件写入时,写到一半掉电的问题。
Doublewrite Buffer是在共享表空间中,也是磁盘文件,是顺序写入,开销不是很大。写入各个表的空间文件时,写入是离散的。对于redo log不需要这样应该写入redolog 是原子性操作一次写512字节,也就是磁盘IO的最小单位,所以无所谓数据损坏。
Doublewrite Buffer用法:
1.如果是写doublewrite buffer本身失败,那么这些数据不会被写到磁盘,InnoDB此时会从磁盘载入原始的数据,然后通过InnoDB的事务日志来计算出正确的数据,重新 写入到doublewrite buffer.
2. 如果 doublewrite buffer写成功的话,但是写磁盘失败,InnoDB就不用通过事务日志来计算了,而是直接用buffer的数据再写一遍.
海量数据不在乎一些错误时,可以关闭Doublewrite Bufffer。
Redo Log
默认情况下有两个名为ib_logfile0和ib_logfile1,这两个是redo log file。 它可以循环写,用于恢复数据写入。恢复提交事务修改的页操作,通常是物理日志,记录的是页的物理修改操作,回复速度比逻辑日志块,如binlog二进制日志。
redo log写入时机innodb_flush_log_at_trx_commit:
- 默认,提交事务时旧将重做日志缓冲同步写到磁盘,即伴有fsync调用。
- 将重做日志异步写到磁盘,写到文件系统缓存中,如果Mysql宕机而操作系统没有故障时,可以恢复。
- 等待master thread定时刷新重做缓存到磁盘。
所以,为了保障事务持久性,必须设置为1.除非海量数据写入不需要保障持久性,丢失一些数据无所谓,追求速度时,可以有其他选择。 0和2的区别在于,
undo log
undo log用于回滚事务,不用于数据恢复。它存储于共享表空间或者undo 表空间文件(.ibd)中,存储在回滚块(rollback segment)中。
作用:
1.undo log回滚记录到某个特定版本,是逻辑日志,根据每行的记录进行记录。它实际上做的是与之前相反的工作。对于Insert会执行一个DELETE,对于UPDATE会执行一个相反的UPDATE.
2. MVCC,实现非锁定读取。
undo log也会产生redo log,因为undo log页需要持久性的保护。
undo log分为insert undo log和update undo log,delete操作也算update。
insert的undo log可以在事务提交后直接删除,不需要purge操作。
update 和delete 的undo log可能需要提供MVCC机制,所以不能在事务提交时删除,提交时后放入undo log链表,等待purge线程做最后删除。undo log会记录事务的ID。
磁盘管理
磁盘IO
InnoDB尽可能使用异步磁盘I / O,通过创建许多线程来处理I / O操作,同时允许其他数据库操作在I / O仍在进行时继续进行。在Linux和Windows平台上,InnoDB使用可用的OS和库函数来执行“本机”异步I / O.
预读Read-Ahead
局部原理。
1.在顺序预读中,如果InnoDB注意到表空间中某个段的访问模式是顺序的,则它会预先将一批数据库页的读取发送到I / O系统。
2.在随机预读中,如果InnoDB注意到表空间中的某些区域似乎正在完全读入缓冲池,则会将剩余的读取发送到I / O系统。
分区
分区不是由存储引擎层完成的。
分区类型
1.RANGE 分区,行数据根据属于一个特定连续区间的列值被放入分区。通常用于根据日期进行分区。
2.LIST分区,和RANGE类似,只是基于枚举值,离散的进行分区。
3.HASH分区,通常用来根据主键的hash进行分区。
4.KEY分区,和HASH分区类似,不同在于使用用户定义的函数进行分区。
启用分区后,表不再由一个ibd文件组成了,而是由多个分区ibd文件组成,物理上分割开来。
分区与分表的区别
分区的话,划分逻辑在db层,分表在业务层。
提高性能的侧重点,分区是Mysql为了突破磁盘IO的瓶颈,分表后是为了突破Mysql的瓶颈,提高mysql的并发能力。
实现上分区更简单,分表更复杂。
内存结构
Buffer Pool
- 新插入到缓存中的页放到中间,放到列表的五分之八处。因为如果直接把读取到的页放到首部,那么某些不是热点数据的SQL会导致缓存中的热点数据被刷出,影响缓存效率。
- 新访问的数据会放到头部
Change Buffer
由于辅助索引页的插入通常是随机访问的,效率比较低。然后对于不存在于buffer pool中的辅助索引页的更改,会把变更缓存起来,等这页被加载到buffer pool的时候再合并写入,或者由purge线程来刷入。
自适应哈希索引:
Innodb会监控缓冲池中的查询,根据访问频率为某些热点页建立哈希索引。根据访问模式(where的条件)的频率,就像以请求参数的hash作为key一样。
log buffer:
事务没有提交时,会把redo log写入log buffer,然后定期写入磁盘。
The log buffer is the memory area that holds data to be written to the log files on disk. Log buffer size is defined by the innodb_log_buffer_size variable. The default size is 16MB. The contents of the log buffer are periodically flushed to disk. A large log buffer enables large transactions to run without the need to write redo log data to disk before the transactions commit. Thus, if you have transactions that update, insert, or delete many rows, increasing the size of the log buffer saves disk I/O.
mysql 事务是怎么保证ACID的
A COMMIT statement.ROLLBACK statement.
C InnoDB doublewrite buffer. InnoDB crash recovery.
I SET ISOLATION LEVEL statement.
D :
- InnoDB doublewrite buffer,
- Configuration option innodb_flush_log_at_trx_commit 重做日志刷新到磁盘。
- Configuration option sync_binlog.
- Write buffer in a storage device, such as a disk drive, SSD, or RAID array.
- Battery-backed cache in a storage device.
- The operating system used to run MySQL, in particular its support for the fsync() system call.