目录
查看MySQL使用的存储引擎
磁盘文件
系统表空间
用户表空间
InnoDB逻辑存储结构
RedoLog文件
内存结构
缓冲池Buffer Pool
RedoLogBuffer
ChangeBuffer
Double Write
CheckPoint机制下的脏页落盘
RedoLog落盘
```sql
show engines;
```
对于存储引擎的选择,大部分情况下,InnoDB都是正确的选择。除非需要用到某些InnoDB不具备的特性,并且没有其他办法可以替代,否则都应该选择InnoDB引擎。InnoDB存储引擎由 内存池,后台线程 和 磁盘文件三大部分组成。
InnoDB的主要的磁盘文件主要分为三大块:一是 系统表空间,二是 用户表空间,三是 redo日志文件和归档文件。 二进制文件(binlog)等文件是MySQL Server层维护的文件,所以未列入InnoDB的磁盘文件中。
系统表空间是由一个或者多个数据文件组成。
默认情况下,一个初始大小为10MB,名为ibdata1的系统数据文件在MySQL的data目录下被创 建。
系统表空间包含 InnoDB数据字典(元数据以及相关对象)、double write buffer、change buffer、undo logs的存储区域。 系统表空间也默认包含任何用户在系统表空间创建的表数据和索引数据。
undo log表空间可以通过参数设置,从系统表空间单独移出去
-- 对系统表空间文件数量和大小的设置
SHOW VARIABLES LIKE 'innodb_data_file_path';
如果设置了参数innodb_file_per_table,则用户可以为每个表产生一个独立的用户表空间。
用户表空间的命名规则为:表名.ibd
-- 用户独立表空间开启配置
SHOW VARIABLES LIKE 'innodb_file_per_table';
通过这种方式,用户不用将所有数据都存放于默认的系统表空间中。
用户表空间只存储该表的 数据、索引 信息,其余信息还是存放在默认的系统表空间中。
InnoDB存储引擎逻辑存储结构可分为五级:表空间、段、区、页、行。
表空间是由各个段组成的,常见的段有数据段、索引段、回滚段等。
-- 叶大小的配置
show global variables like 'innodb_page_size';
root@VM-0-14-ubuntu:/var/lib/mysql# getconf PAGE_SIZE
4096
所以InnoDB从磁盘中读取一个数据页时,操作系统会分4次从磁盘文件中读取数据到内存。写入也是 一样的,需要分4次从内存写入到磁盘中。
-- 查看表tuser数据行的格式
SHOW TABLE STATUS LIKE 'tuser';
当InnoDB的数据存储文件发生错误时,重做日志文件就能派上用场。InnoDB存储引擎可以使用重 做日志文件将数据恢复为正确状态,以此来保证数据的正确性和完整性。
每个InnoDB存储引擎至少 有1个重做日志文件组(group),每个文件组下至少有2个重做日志文件,如默 认的 ib_logfile0 和 ib_logfile1。 在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。 InnoDB存储引擎先写入重做日志文件1,当文件被写满时,会切换到重做日志文件2,再当重做日 志文件2也被写满时,再切换到重做日志文件1。
-- 重做日志文件的大小
SHOW VARIABLES LIKE 'innodb_log_file_size';
-- 重做日志文件的数量
SHOW VARIABLES LIKE 'innodb_log_files_in_group';
缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲(insert buffer)、 自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息(lock info)和数据字典信息(data dictionary)。
-- 缓冲池大小
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- 额外内存池
SHOW VARIABLES LIKE 'innodb_additional_mem_pool_size';
InnoDB在缓冲池中变更数据时,会首先将相关变更写入重做日志缓冲中,然后再按 时或者当事务提交时写入磁盘(RedoLog落盘机制),这符合Force-log-at-commit原则; 当重做日志写入磁盘后,缓冲池中的变更数据才会依据checkpoint机制择时写入到磁盘中(脏页落盘机制),这符 合WAL原则。
操作系统的文件系统是带有缓存的,当InnoDB向磁盘写入数据时,有可能只是写入到了文件系统的缓存 中,没有真正的“落袋为安”。
在InnoDB引擎上进行插入操作时,一般需要按照主键顺序进行插入,这样才能获得较高的 插入性能。对于次要索引的插入或者更新操作,先判断插入的非主键索引是否在缓冲池中,若在,则直接插入;若不在,则 先放入到一个Change Buffer中。然后再以一定的频率和情况进行Change Buffer和非聚簇索引页子节点的合并操 作。
checkpoint触发时机:
当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁 盘。数据库只需对Checkpoint后的重做日志进行恢复,这样就大大缩短了恢复的时间。
当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行 Checkpoint,将脏页也就是页的新版本刷回磁盘。
当重做日志出现不可用时,因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让 其无限增大的。重做日志可以被重用的部分是指这些重做日志已经不再需要,当数据库发生宕机 时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。如果重做日志还需 要使用,那么必须强制Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
checkpoint分类:
sharp checkpoint:在关闭数据库的时候,将buffer pool中的脏页全部刷新到磁盘中。
fuzzy checkpoint:数据库正常运行时,在不同的时机,将部分脏页写入磁盘。仅刷新部分脏页到 磁盘,也是为了避免一次刷新全部的脏页造成的性能问题。
-- 空闲页的数量
show variables like 'innodb_lru_scan_depth';
-- 脏页的数量
show variables like 'innodb_max_dirty_pages_pct';
InnoDB在缓冲池中变更数据时,会首先将相关变更写入重做日志缓冲中,然后再按 时或者当事务提交时写入磁盘RedoLog文件。当缓冲池中的页的版本比磁盘要新时(脏页),数据库需要将新版本的页从缓冲池刷新到磁盘表空间
ChangeBuffer给InnoDB存储引擎带来了性能上的提升,那么Double Write带给InnoDB存储引擎 的是数据页的可靠性
对缓冲池的脏页进行落盘时,并不直接写磁盘,而是
数据更新流程:
RedoLog落盘机制
RedoLogBuffer写入磁盘的时机,由参数 innodb_flush_log_at_trx_commit 控制,默认是 1,表示 事务提交后立即落盘。
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';
0:MySQL每秒一次将数据从log buffer写入日志文件并同时fsync刷新到磁盘中。 每次事务提交时,不会立即把 log buffer 里的数据写入到redo log日志文件的。如果 MySQL崩溃或者服务器宕机,此时内存里的数据会全部丢失,最多会丢失1秒的事务。(定时1s刷一次)
1:每次事务提交时,MySQL将数据将从log buffer写入日志文件并同时fsync刷新到磁盘 中。 该模式为系统默认,MySQL崩溃已经提交的事务不会丢失,要完全符合ACID,必须使用默认设置1。(写一次刷一次)
2:每次事务提交时,MySQL将数据从log buffer写入日志文件,MySQL每秒执行一次fsync 操作将数据同步到磁盘中。( 先写入操作系统文件缓冲区,由操作系统决定刷盘时机 )