mysql系列之InnoDB存储引擎的磁盘结构

前言

以前已经介绍了InnoDB总体的结构,并详细介绍了InnoDB内存结构的各个组成部分及其做用,今天继续分析InnoDB存储引擎的磁盘结构。java


1、InnoDB的磁盘结构

在这里插入图片描述

InnoDB的磁盘结构主要由如下几部分组成:
一、表
二、索引
三、表空间
四、Doublewrite Buffer
五、Redo Log
六、Undo Logs


2、表空间

InnoDB采用将存储的数据按表空间(tablesspace)进行存放的设计。简单来讲,表空间就是mysql中各种数据存放的目录,默认状况下表空间的目录就是数据目录。mysql

InnoDB下有如下5种表空间:
web

在这里插入图片描述

一、系统表空间  The System Tablespace

系统表空间是存放change buffer的区域。
Change Buffer是缓存那些不在buffer pool里的辅助索引的变化的特殊数据结构 。
在磁盘上,Change Buffer是system tablespace(系统表空间)的一部分,当数据库宕机时,索引的变动会被缓冲到磁盘的Change Buffer区域。sql

若是表是在系统表空间中建立的,而不是单表单文件表空间或常规表空间,则系统表空间中还会保存表和索引的数据。shell

在早期的MySQL版本中,系统表空间包含InnoDB数据字典。在MySQL 8.0中,InnoDB将元数据存储在MySQL数据字典中。
在早期的MySQL版本中,系统表空间还包含doublewrite缓冲存储区。从MySQL 8.0.20开始,该区域驻留在单独的doublewrite文件中。数据库

系统表空间能够有一个或多个数据文件,默认状况下,有一个单独的数据文件被建立在数据目录下,名称为:iddata1缓存

说明:
MySQL8开始删除了原来的frm文件,并采用 Serialized Dictionary Information (SDI), SDI是MySQL8.0从新设计数据词典后引入的新产物,并开始已经统一使用InnoDB存储引擎来存储表的元数据信息。SDI信息源记录保存在ibd文件中。安全

二、单表单文件表空间

InnoDB默认状况下就启用了单表单文件表空间,每一个表的数据和索引都会采用单独的文件进行保存。
是否启动 file-per-table表空间是由innodb_file_per_table属性来控制的。服务器

示例:
配置文件设置:微信

[mysqld]
innodb_file_per_table=ON

命令行设置:

mysql> SET GLOBAL innodb_file_per_table=ON;

建立表test:

mysql> USE test;
mysql> CREATE TABLE t1 (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100)

) ENGINE 
= InnoDB;

shell> cd /path/to/mysql/data/test
shell> ls
t1.ibd

数据存储文件.idb文件会根据代表来命名(table_name.ibd)

单表单文件表空间的好处是
一、在单表单文件的表空间下,删除或者清空表后,存储空间会马上返回给操做系统。而在共享表空间下,表空间数据文件的大小不会缩小。

二、对共享表空间下的表进行修改操做时,会增长表空间的磁盘空间。该空间不会像单表单文件表空间那样释放回操做系统。

三、清空表(TRUNCATE TABLE)的操做性能更好。

四、File-per-table表空间数据文件能够建立在不一样的存储设备,对于I/O优化,空间管理,或备份操做都更加方便。

五、能够经过复制File-per-table表空间的对应表的数据文件到其余mysql数据库实例的表空间下,实现表的导入迁移。

六、File-per-table表空间中建立的表支持与DYNAMIC和压缩行格式

七、File-per-table表空间能够节省故障恢复时间,提升数据损坏恢复的成功概率。

八、更快速的备份机制,不用中断其余表的正在使用的InnoDB表。

九、可以经过监视文件的大小来监视表的大小。

十、常见的LInux文件系统不容许并发写入单个文件(例如共享表空间)。File-per-table表空间提升了并发读写入性能。

十一、共享表空间中的表的大小受到64TB表空间大小限制的限制。相比之下,每一个
每表文件表空间的大小限制为64TB,这为单个表的增加提供了足够的空间
在尺寸方面。

坏处:
一、可能存在空间浪费

二、fsync操做在每一个表的多个数据文件上执行,而不是在单个共享上执行
表空间数据文件。因为fsync操做是针对每一个文件的,所以没法对多个表进行写操做
组合在一块儿,可能会致使fsync操做总数增长。

三、mysqld进程必须为每一个表文件表空间保留一个打开的文件句柄,这可能会对性能有必定影响。

四、会产生更多的磁盘碎片,可能会影响drop table和表扫描的性能。

三、常规表空间

常规表空间是使用CREATE TABLESPACE语法建立的共享InnoDB表空间

常规表空间和系统表空间相似,也是共享的表空间,一个文件可以存储多个表数据。
相比File-per-table表空间,常规表空间因为多表共享表空间,消耗的内存会更少一点,具备潜在的内存优点。(占用的磁盘空间会更小)

常规表空间提供了相似File-per-table表空间的多个数据文件和的存储管理功能。好比能够建立多个常规表空间,而后将表分散的建立在多个常规表空间中。

mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;
mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1;
mysql> DROP TABLE t1;
mysql> DROP TABLESPACE ts1;

四、Undo表空间

回滚表空间,用来保存回滚日志,即undo logs。
回滚表空间(undo tablespaces)的默认路径是mysql的数据存储路径,会在undo tablespaces下生成undo_001和undo002共2个文件。
可经过配置能够经过 innodb_undo_directory属性主动设定回滚表空间的位置。
在MySQL8.0.14后,能够经过 CREATE UNDO TABLESPACE主动建立回滚表空间。

CREATE UNDO TABLESPACE tablespace_name ADD DATAFILE 'file_name.ibu';

回滚表空间的文件必须以".ibu"做为扩展后缀名。

删除回滚表空间:

ALTER UNDO TABLESPACE tablespace_name SET INACTIVE;
DROP UNDO TABLESPACE tablespace_name;

四、临时表空间(Temporary Tablespaces)

InnoDB使用会话临时表空间和全局临时表空间。

4.一、会话临时表空间 Session Temporary Tablespaces
会话临时表空间存储用户建立的临时表和内部临时表的相关信息。
当InnoDB配置为磁盘内部的存储引擎时,由优化程序建立
临时表。好比大表的join查询时,可能就会自动建立临时表来辅助查询。

MySQL 8.0.13后,新增长了INFORMATION_SCHEMA.INNODB_SESSION_TEMP_TABLESPACES表用来保存相关会话临时表的信息。

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SESSION_TEMP_TABLESPACES;
+----+------------+----------------------------+-------+----------+-----------+
| ID | SPACE | PATH | SIZE | STATE | PURPOSE |
+----+------------+----------------------------+-------+----------+-----------+
| 8 | 4294566162 | ./#innodb_temp/temp_10.ibt | 81920 | ACTIVE | INTRINSIC |
| 8 | 4294566161 | ./#innodb_temp/temp_9.ibt | 98304 | ACTIVE | USER |
| 0 | 4294566153 | ./#innodb_temp/temp_1.ibt | 81920 | INACTIVE | NONE |
| 0 | 4294566154 | ./#innodb_temp/temp_2.ibt | 81920 | INACTIVE | NONE |
| 0 | 4294566155 | ./#innodb_temp/temp_3.ibt | 81920 | INACTIVE | NONE |
| 0 | 4294566156 | ./#innodb_temp/temp_4.ibt | 81920 | INACTIVE | NONE |
| 0 | 4294566157 | ./#innodb_temp/temp_5.ibt | 81920 | INACTIVE | NONE |
| 0 | 4294566158 | ./#innodb_temp/temp_6.ibt | 81920 | INACTIVE | NONE |
| 0 | 4294566159 | ./#innodb_temp/temp_7.ibt | 81920 | INACTIVE | NONE |
| 0 | 4294566160 | ./#innodb_temp/temp_8.ibt | 81920 | INACTIVE | NONE |
+----+------------+----------------------------+-------+----------+-----------+

4.2 全局临时表空间 Global Temporary Tablespace
全局临时表空间(ibtmp1)存储对用户建立的临时表的修改操做的回滚段信息。
能够经过innodb_temp_data_file_path属性指定临时表空间的位置。

mysql> SELECT @@innodb_temp_data_file_path;
+------------------------------+
| @@innodb_temp_data_file_path |
+------------------------------+
| ibtmp1:12M:autoextend |
+------------------------------+
To check the size of global temporary tablespace

在my.conf中配置临时表空间:

[mysqld]
innodb_temp_data_file_path=ibtmp1:12M:autoextend:max:500

经过INFORMATION_SCHEMA.FILES表查看元数据文件信息。

mysql> SELECT FILE_NAME, TABLESPACE_NAME, ENGINE, INITIAL_SIZE, TOTAL_EXTENTS*EXTENT_SIZE
 AS TotalSizeBytes, DATA_FREE, MAXIMUM_SIZE FROM INFORMATION_SCHEMA.FILES
 WHERE TABLESPACE_NAME = 'innodb_temporary'\G
*************************** 1. row ***************************
 FILE_NAME: ./ibtmp1
TABLESPACE_NAME: innodb_temporary
 ENGINEInnoDB
 INITIAL_SIZE: 12582912
 TotalSizeBytes: 12582912
 DATA_FREE: 6291456
 MAXIMUM_SIZE: NULL

3、双写缓冲  Doublewrite Buffer

doublewrite缓冲区是一个存储区域,InnoDB在将页面写入InnoDB数据文件中的适当位置以前,会在其中写入从缓冲池中刷新的页面。
若是在页面写入过程当中发生操做系统,存储子系统或mysqld进程崩溃,则InnoDB能够在崩溃恢复期间从doublewrite缓冲区中找到该页面的良好副本。

在MySQL 8.0.20以前,doublewrite缓冲区存储区位于InnoDB系统表空间中。从MySQL 8.0.20开始,doublewrite缓冲区存储区位于doublewrite文件中。

从MySQL 8.0.20开始,默认会建立2个Doublewrite Buffer文件。

#ib_16384_0.dblwr
#ib_16384_1.dblwr

InnoDB存储引擎数据双写的流程说明:


正是因为Doublewrite Buffer机制,极大的保障了Innodb引擎的数据安全性。尽管出现了宕机坏页的状况,也能够从Doublewrite Buffer读取正常页来恢复。


为何有了redo,还要Doublewrite Buffer机制?数据库双写的好处是什么?
Doublewrite Buffer机制主要是更大的保障了数据页的可靠性。主要是解决部分写失效的问题。好比16KB的页,只写了前面4KB,以后就发生宕机了,这种状况被称为部分写失效。
针对部分写失效的问题,redo重作日志也不能解决这个问题。

4、重作日志  Redo Log

重作日志是基于磁盘的数据结构,主要做用是在崩溃恢复期间用于纠正不完整事务写入的数据。在正常操做期间,重作日志对更改表数据的请求进行编码记录,这些请求是由SQL语句或低级API调用引发的。在初始化期间以及接受链接以前,会自动重播未完成意外关闭以前未完成更新数据文件的修改。
默认状况下,redo log会自动生成2个文件:

ib_logfile0
ib_logfile1

WAL(Write-Ahead Logging)机制
WAL 的全称是 Write-Ahead Logging,中文称预写式日志,是一种数据安全写入机制。就是先写日志,而后在写入磁盘,这样保证数据的安全性。Mysql中的Redo Log就是采用WAL机制。(这里的写日志因为是顺序写,因此不会成为性能瓶颈。)

WAL做用
  Mysql中若是为了保证数据的持久性,在每提交一个事务就将日志刷新到磁盘上,这样效率就过低了,严重影响性能,因此就有了Write-Ahead 。
  Write-Ahead工做机制:
    先在内存中提交事务,而后写日志(在InnoDB中就是Redo Log,日志是为了防止宕机致使内存数据丢失),而后再后台任务中把内存中的数据异步刷到磁盘。

5、回滚日志  Undo Log

回滚日志主要是为了支持事务回滚功能。

默认会生成2个回滚日志,保存在undo tablespaces,默认状况下就在数据目录下:

undo_001
undo_002

一个事务最多能够分配四个撤消日志,如下每种操做类型均可以分配一个:
一、对用户自定义表执行插入操做
二、对用户自定义表执行删除和更新操做
三、对用户自定义的临时表执行插入操做
四、对用户自定义的临时表执行删除和更新操做

补充说明一:全文索引

全文索引:

mysql> CREATE TABLE opening_lines (
 id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
 opening_line TEXT(500),
2830
Indexes
 author VARCHAR(200),
 title VARCHAR(200),
 FULLTEXT idx (opening_line)
 ) ENGINE=InnoDB;
mysql> SELECT table_id, namespace from INFORMATION_SCHEMA.INNODB_TABLES
 WHERE name LIKE 'test/%';
+----------+----------------------------------------------------+-------+
| table_id | name | space |
+----------+----------------------------------------------------+-------+
| 333 | test/fts_0000000000000147_00000000000001c9_index_1 | 289 |
| 334 | test/fts_0000000000000147_00000000000001c9_index_2 | 290 |
| 335 | test/fts_0000000000000147_00000000000001c9_index_3 | 291 |
| 336 | test/fts_0000000000000147_00000000000001c9_index_4 | 292 |
| 337 | test/fts_0000000000000147_00000000000001c9_index_5 | 293 |
| 338 | test/fts_0000000000000147_00000000000001c9_index_6 | 294 |
| 330 | test/fts_0000000000000147_being_deleted | 286 |
| 331 | test/fts_0000000000000147_being_deleted_cache | 287 |
| 332 | test/fts_0000000000000147_config | 288 |
| 328 | test/fts_0000000000000147_deleted | 284 |
| 329 | test/fts_0000000000000147_deleted_cache | 285 |
| 327 | test/opening_lines | 283 |
+----------+----------------------------------------------------+-------+

补充说明二:二进制日志(binlog)

binlog是记录全部数据库表结构变动(例如CREATE、ALTER TABLE…)以及表数据修改(INSERT、UPDATE、DELETE…)的二进制日志。

binlog不会记录SELECT和SHOW这类操做,由于这类操做对数据自己并无修改,但你能够经过查询通用日志来查看MySQL执行过的全部语句。

二进制日志包括两类文件:二进制日志索引文件(文件名后缀为.index)用于记录全部的二进制文件,二进制日志文件(文件名后缀为.00000*)记录数据库全部的DDL和DML(除了数据查询语句)语句事件。

MySQL中的二进制日志主要有两个功能:数据恢复和数据复制。

数据恢复--MySQL自己具有数据备份和恢复功能。例如咱们能够天天午夜12:00进行数据备份。可是,此类备份功能并非对数据库的实时备份,若是数据库在下午17:00出现故障没法恢复,那么从前一天午夜12:00到当天下午17:00的数据库内容将丢失。经过二进制日志能够解决这个问题。能够经过前一天午夜12:00的数据库备份文件恢复数据库,而后使用二进制日志恢复从前一天午夜12:00到当天下午17:00的数据库内容。

数据复制--MySQL支持主从服务器间的数据复制功能,并经过该功能实现数据库的冗余机制以保证数据库的可用性和提升数据库的性能。MySQL正是经过主服务器的二进制日志来实现数据的传递。主服务器上的二进制日志内容会被发送到各个从服务器,并在每一个从服务器上执行,从而保证了主从服务器之间数据的一致性。

在默认配置下,MySQL不记录二进制日志。能够经过设置参数--log-bin=[base_name]启用二进制日志功能

补充说明三:数据和回滚日志的逻辑存储结构

Page是Innodb存储的最基本结构,也是Innodb磁盘管理的最小单位,与数据库相关的全部内容都存储在Page结构里。Page分为几种类型:数据页(B-Tree Node),Undo页(Undo Log Page),系统页(System Page),事务数据页(Transaction System Page)等;每一个数据页的大小为16kb,每一个Page使用一个32位(一位表示的就是0或1)的int值来表示,正好对应Innodb最大64TB的存储容量(16kb * 2^32=64tib)


6、查看mysql数据目录下的文件

默认配置下,mysql8.0.11数据目录下相关数据文件说明:



7、经过sql语句查看表空间相关信息

-- 查看数据库版本
select VERSION();

-- 查看表空间数据文件信息
SELECT * FROM INFORMATION_SCHEMA.FILES WHERE TABLESPACE_NAME='innodb_temporary';

-- 查看全部表空间信息
SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES;

-- 表空间的名称和路径
SELECT * FROM  INFORMATION_SCHEMA.INNODB_TABLESPACES_BRIEF;

-- 查看全部Innodb引擎表
SELECT * from INFORMATION_SCHEMA.INNODB_TABLES;

-- 查看全部Innodb引擎下的临时表信息
SELECT * FROM INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO;

总结

一、InnoDB采用表空间(tablesspace)的形式管理数据存放。
二、InnoDB有5类表空间:系统表空间(System Tablespace),单表单文件表空间(File-Per-Table Tablespaces)、常规表空间(General Tablespaces)、回滚表空间(Undo Tablespaces)、临时表空间(Temporary Tablespaces)
三、InnoDB经过重作日志(redo log)和双写缓冲 (Doublewrite Buffer)保证了数据的安全性,在事务中断、数据库宕机、数据页出现部分写失效的问题状况下能正常恢复。
四、经过回滚日志(Undo log),能够支持事务回滚和多版本控制机制(MVCC)。
五、了解日志预习机制WAL(Write-Ahead Logging),顺序写,fsync,双写缓冲(Doublewrite Buffer)等数据库优化机制

更多精彩,关注我吧。

图注:跟着老万学java



本文分享自微信公众号 - 跟着老万学java(douzhe_2019)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索