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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索