mysql表空間結(jié)構(gòu)和日志的用途詳解
日志是mysql
數(shù)據(jù)庫的重要組成部分,記錄著數(shù)據(jù)庫運行期間各種狀態(tài)信息。mysql
日志主要包括錯誤日志、查詢?nèi)罩尽⒙樵內(nèi)罩?、事?wù)日志、二進(jìn)制日志幾大類。
以下是mysql數(shù)據(jù)庫中常用的幾種日志類型:
關(guān)于每種日志的類型的功能可參考:
關(guān)于如何查詢?nèi)罩臼欠耖_啟,可使用以下命令:
MySQL 中的binlog和redolog是兩種核心日志機制,它們在數(shù)據(jù)庫的數(shù)據(jù)持久化、主從復(fù)制和崩潰恢復(fù)中扮演關(guān)鍵角色。
關(guān)于兩者如何進(jìn)行相互聯(lián)系的,可參考如下:
1、表空間結(jié)構(gòu)
1.1、分類
MySQL數(shù)據(jù)表以文件方式存放在磁盤中,默認(rèn)使用共享表空間(0)存儲。
1.對于 InnoDB:
ibdata 文件:
當(dāng)使用共享表空間時,所有表的數(shù)據(jù)和索引會存儲在一個共享的 ibdata 文件中。表結(jié)構(gòu)以.frm
文件的形式存儲在與表對應(yīng)的文件夾中。
.ibd 文件:
如果使用了獨立表空間,InnoDB 會將每個表的結(jié)構(gòu)和數(shù)據(jù)存儲在獨立的 .ibd 文件中。每當(dāng)表的數(shù)據(jù)或索引被更新時,文件也會隨之變化。表的結(jié)構(gòu)仍然以.frm
文件存儲。
2.對于 MyISAM:
每個表的數(shù)據(jù)和索引不屬于共享空間或獨立空間的問題,而是直接通過三個文件來管理的:
MyISAM 數(shù)據(jù)表通常使用三種文件,分別是:
- .frm:存儲表的結(jié)構(gòu)信息。
- .MYD:存儲表的數(shù)據(jù)。
- .MYI:存儲表的索引。
3. 設(shè)置
使用共享表空間:
- 只需將innodb_file_per_table設(shè)置為0或不設(shè)置(默認(rèn)值)。
使用獨立表空間:
- 可以在 MySQL 配置文件(my.cnf或my.ini)中啟用獨立表空間,添加如下配置:
[mysqld] innodb_file_per_table=1
這將允許每個 InnoDB 表都有其獨立的.ibd
文件。
1.2、物理結(jié)構(gòu)
如下圖所示:
獨立表空間文件(.ibd),每個獨立表在磁盤上對應(yīng)一個.ibd文件(test_table.ibd)
主要包括以下部分:
1.表空間頭(Header)
存儲表空間的基本信息,如:
- 表空間 ID。
- 區(qū)(Extent)的分配狀態(tài)。
- 空閑列表(Free List)、碎片列表(Fragment List)等。
用于管理表空間的物理分配和回收。
2.段(Segment)
InnoDB 的存儲結(jié)構(gòu)是分層的:段 → 區(qū) → 頁。每個表空間文件包含多個段,主要分為以下幾類:
數(shù)據(jù)段(Data Segment):
- 存儲 B+ 樹的葉子節(jié)點(數(shù)據(jù)頁),即實際的行數(shù)據(jù)。
- 對于主鍵索引(聚簇索引),數(shù)據(jù)段直接存儲完整的行數(shù)據(jù)。
索引段(Index Segment):
- 存儲 B+ 樹的非葉子節(jié)點(索引頁),即索引鍵值和子節(jié)點指針。
- 用于加速數(shù)據(jù)檢索。
回滾段(Rollback Segment):
- 存儲事務(wù)的Undo Log(回滾數(shù)據(jù)),用于實現(xiàn)事務(wù)回滾和 MVCC(多版本并發(fā)控制)。
- 每個事務(wù)可能關(guān)聯(lián)一個或多個回滾段。
3.區(qū)(Extent)
每個段由多個區(qū)(Extent)組成,一個區(qū)固定包含64 個連續(xù)頁(默認(rèn)頁大小為 16KB,因此一個區(qū)大小為 1MB)。
區(qū)是 InnoDB 分配存儲空間的基本單位,用于提高分配效率。
4.頁(Page)
頁是 InnoDB 的最小存儲單元,大小默認(rèn)為16KB。
如下圖所示:
頁的類型取決于其所屬的段:
- 數(shù)據(jù)頁:存儲 B+ 樹葉子節(jié)點的數(shù)據(jù)(如主鍵索引的行數(shù)據(jù))。
- 索引頁:存儲 B+ 樹非葉子節(jié)點的索引鍵值和子節(jié)點指針。
- 回滾頁:存儲 Undo Log(回滾數(shù)據(jù))。
- 系統(tǒng)頁:存儲表空間的元數(shù)據(jù)(如空閑列表、區(qū)分配信息等)。
5.空閑列表(Free List)
- 記錄表空間中未被使用的頁,供后續(xù)分配。
- 當(dāng)插入新數(shù)據(jù)或更新索引時,InnoDB 會從空閑列表中分配頁。
小結(jié)
一張表的空間由頁節(jié)點段、非頁節(jié)點段、回滾段、和表空間組成。頁節(jié)點段由多個區(qū)(1MB)組成,每個區(qū)由64個頁(16KB)組成,每個頁有多行組成。
如下圖所示:
注意:此處圖中的頁僅代表的是葉子結(jié)點的page頁。對于非葉子節(jié)點,也有相應(yīng)的索引鍵值的頁。
1.3、邏輯結(jié)構(gòu)
B+ 樹索引與數(shù)據(jù)組織,InnoDB 的表邏輯上通過B+ 樹索引組織數(shù)據(jù)。
具體如下:
1.主鍵索引(聚簇索引)
- 葉子節(jié)點:存儲完整的行數(shù)據(jù)(包括所有列的值)。
- 非葉子節(jié)點:存儲主鍵值和指向子節(jié)點的指針。
- 聚簇索引決定了數(shù)據(jù)在磁盤上的物理存儲順序,因此主鍵選擇直接影響性能。
2.二級索引(輔助索引)
- 葉子節(jié)點:存儲主鍵值(而非完整行數(shù)據(jù))。
- 非葉子節(jié)點:存儲索引鍵值和子節(jié)點指針。
- 查詢時,InnoDB 會先通過二級索引定位到主鍵值,再通過聚簇索引查找完整行數(shù)據(jù)。
3.事務(wù)與 MVCC 機制
Undo Log(回滾段中的頁):
- 記錄事務(wù)修改前的數(shù)據(jù)版本。
- 支持事務(wù)回滾(Rollback)和并發(fā)讀?。∕VCC)。
版本鏈(Version Chain):
- 每個行記錄通過 Undo Log 構(gòu)建版本鏈,供不同事務(wù)讀取一致性視圖。
關(guān)于獨立表和共享表的區(qū)別:
2、binlog
2.1. 定義
binlog(Binary Log)是 MySQL 的服務(wù)層日志,屬于二進(jìn)制日志,記錄所有對數(shù)據(jù)庫的增刪改操作(不包含查詢)。由 MySQL Server 層生成,與存儲引擎無關(guān)(如 InnoDB、MyISAM)。默認(rèn)情況下二進(jìn)制日志是關(guān)閉的。
結(jié)構(gòu)如下所示:
2.2. 核心作用
1.主從復(fù)制(Replication)
主庫將 binlog 發(fā)送給從庫,從庫重放 binlog 實現(xiàn)數(shù)據(jù)同步。
2.數(shù)據(jù)恢復(fù)(Point-in-Time Recovery)
通過 binlog 恢復(fù)到某個時間點的數(shù)據(jù)狀態(tài)。
2.3. 存儲位置
默認(rèn)存儲在 MySQL 數(shù)據(jù)目錄下的mysql-bin.xxxxxx
文件中。
binlog
是通過追加的方式進(jìn)行寫入的,可以通過max_binlog_size
參數(shù)設(shè)置每個binlog
文件的大小,當(dāng)文件大小達(dá)到給定值之后,會生成新的文件來保存日志。
如下圖所示:
mysql> show binary logs; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000001 | 201 | | mysql-bin.000002 | 154 | +------------------+-----------+ 2 rows in set (0.00 sec)
2.4. 格式
在MySQL 5.7.7
之前,默認(rèn)的格式是STATEMENT
,MySQL 5.7.7
之后,默認(rèn)值是ROW
。日志格式通過binlog-format
指定。
可使用以下命令,查看到:
- Row-based:記錄每一行的變更(5.7.7后默認(rèn))。
- Statement-based:記錄 SQL 語句(5.7.7之前默認(rèn))。
- Mixed:混合模式。
三種不同格式的優(yōu)缺點:
配置如下:
[mysqld] log-bin=mysql-bin # 開啟 binlog server-id=1 # 主庫 ID
2.5、binlog刷盤時機
對于InnoDB
存儲引擎而言,只有在事務(wù)提交時才會記錄biglog
,此時記錄還在內(nèi)存中,那么biglog
是什么時候刷到磁盤中的呢?
mysql
通過sync_binlog
參數(shù)控制biglog
的刷盤時機,取值范圍是0-N
:
- 0:不去強制要求,由系統(tǒng)自行判斷何時寫入磁盤;
- 1:每次
commit
的時候都要將binlog
寫入磁盤; - N:每N個事務(wù),才會將
binlog
寫入磁盤。
從上面可以看出,sync_binlog
最安全的是設(shè)置是1
,這也是MySQL 5.7.7
之后版本的默認(rèn)值。
設(shè)置一個大一些的值可以提升數(shù)據(jù)庫性能,因此實際情況下也可以將值適當(dāng)調(diào)大,犧牲一定的一致性來獲取更好的性能。
3、redlog
持久性:只要事務(wù)提交成功,那么對數(shù)據(jù)庫做的修改就被永久保存下來了,不可能因為任何原因再回到原來的狀態(tài)。
那么mysql
是如何保證一致性的呢?
在每次事務(wù)提交的時候,將該事務(wù)涉及修改的數(shù)據(jù)頁全部刷新到磁盤中。但是這么做會有嚴(yán)重的性能問題。
主要體現(xiàn)在兩個方面:
- 因為
Innodb
是以頁
為單位進(jìn)行磁盤交互的,而一個事務(wù)很可能只修改一個數(shù)據(jù)頁里面的幾個字節(jié),這個時候?qū)⑼暾臄?shù)據(jù)頁刷到磁盤的話,太浪費資源了! - 一個事務(wù)可能涉及修改多個數(shù)據(jù)頁,并且這些數(shù)據(jù)頁在物理上并不連續(xù),使用隨機IO寫入性能太差!
因此使用redo log
,就是只記錄事務(wù)對數(shù)據(jù)頁做了哪些修改,這樣就能完美地解決性能問題了(相對而言文件更小并且是順序IO)。
關(guān)于流程如下圖所示:
3.1、原理及流程
redo log
包括兩部分:一個是內(nèi)存中的日志緩沖(redo log buffer
),另一個是磁盤上的日志文件(redo logfile
)。
- redolog(Redo Log)是InnoDB 存儲引擎的事務(wù)日志,記錄事務(wù)對數(shù)據(jù)頁的物理修改。
- 用于保證事務(wù)的持久性(Durability),防止數(shù)據(jù)丟失。
mysql
每執(zhí)行一條DML
語句,先將記錄寫入redo log buffer
,后續(xù)某個時間點再一次性將多個操作記錄寫到redo log file
。這種先寫日志,再寫磁盤的技術(shù)就是MySQL
里經(jīng)常說到的WAL(Write-Ahead Logging)
技術(shù)。
在計算機操作系統(tǒng)中,用戶空間(user space
)下的緩沖區(qū)數(shù)據(jù)一般情況下是無法直接寫入磁盤的,中間必須經(jīng)過操作系統(tǒng)內(nèi)核空間(kernel space
)緩沖區(qū)(OS Buffer
)。
因此,redo log buffer
寫入redo logfile
實際上是先寫入OS Buffer
,然后再通過系統(tǒng)調(diào)用fsync()
將其刷到redo log file
中。
過程如下:
可以通過innodb_flush_log_at_trx_commit
參數(shù)配置將redo log buffer
寫入redo log file
的時機,
3.2、核心作用
如下圖所示:
事務(wù)持久化
- 事務(wù)提交時,先將修改寫入 redolog,再異步刷盤到數(shù)據(jù)文件。
崩潰恢復(fù)(Crash Recovery)
- 數(shù)據(jù)庫重啟時,通過 redolog 恢復(fù)未落盤的數(shù)據(jù)。
3.3、存儲位置
- 默認(rèn)存儲在
ib_logfile0
和ib_logfile1
文件中(InnoDB 專屬)。
3.4、特性
- 固定大小:默認(rèn) 4GB(可通過
innodb_log_file_size
配置)。 - 循環(huán)寫入:當(dāng)文件寫滿時,覆蓋舊日志。
- 物理日志:記錄的是數(shù)據(jù)頁的物理修改(如某個頁的某個偏移量被修改)。
redo log
實際上記錄數(shù)據(jù)頁的變更,而這種變更記錄是沒必要全部保存,因此redo log
實現(xiàn)上采用了大小固定,循環(huán)寫入的方式,當(dāng)寫到結(jié)尾時,會回到開頭循環(huán)寫日志。
啟動innodb
的時候,不管上次是正常關(guān)閉還是異常關(guān)閉,總是會進(jìn)行恢復(fù)操作。因為redo log
記錄的是數(shù)據(jù)頁的物理變化,因此恢復(fù)的時候速度比邏輯日志(如binlog
)要快很多。
配置如下:
[mysqld] innodb_log_file_size = 1G # 設(shè)置 redolog 大小 innodb_flush_log_at_trx_commit = 1 # 事務(wù)提交時立即刷盤
關(guān)于redlog buffer的內(nèi)存結(jié)構(gòu)如下:
關(guān)于redlog buffer到redo log file持久化的流程如下圖:
關(guān)于binlog和redlog的區(qū)別聯(lián)系如圖所示:
3.5、聯(lián)系
binlog 與 redolog的聯(lián)系。
1. 事務(wù)提交流程中的協(xié)作
- 事務(wù)執(zhí)行:修改數(shù)據(jù)頁(內(nèi)存中)。
- 寫入 redolog:事務(wù)提交時,將修改寫入 redolog(確保持久性)。
- 寫入 binlog:事務(wù)提交后,將修改寫入 binlog(用于主從復(fù)制和恢復(fù))。
關(guān)鍵區(qū)別:
- redolog 是 InnoDB 的事務(wù)日志,確保事務(wù)的原子性和持久性。
- binlog 是 MySQL 的邏輯日志,用于主從復(fù)制和數(shù)據(jù)恢復(fù)。
2. 數(shù)據(jù)一致性保障
- redolog:確保事務(wù)的修改不會因宕機丟失。
- binlog:確保主從節(jié)點的數(shù)據(jù)一致性。
3. 崩潰恢復(fù)流程
- 恢復(fù) redolog:數(shù)據(jù)庫重啟時,通過 redolog 恢復(fù)未落盤的事務(wù)。
- 恢復(fù) binlog:通過 binlog 恢復(fù)到某個時間點(需結(jié)合 redo log)。
3.6、應(yīng)用場景
1. 主從復(fù)制
- 主庫:將 binlog 發(fā)送給從庫。
- 從庫:重放 binlog 實現(xiàn)數(shù)據(jù)同步。
2. 數(shù)據(jù)恢復(fù)
- 基于 binlog:恢復(fù)到某個時間點(如誤刪數(shù)據(jù)后回滾)。
- 基于 redolog:恢復(fù)未落盤的事務(wù)(數(shù)據(jù)庫崩潰后自動恢復(fù))。
3. 數(shù)據(jù)一致性
- binlog + redolog:共同保證 ACID 中的D(Durability)和主從一致性。
區(qū)別如下所示:
4、undolog
4.1、介紹
原子性底層就是通過undo log
實現(xiàn)的。undo log
主要記錄了數(shù)據(jù)的邏輯變化,比如一條INSERT
語句,對應(yīng)一條DELETE
的undo log
,對于每個UPDATE
語句,對應(yīng)一條相反的UPDATE
的undo log
,這樣在發(fā)生錯誤時,就能回滾到事務(wù)之前的數(shù)據(jù)狀態(tài)。
同時,undo log
也是MVCC
(多版本并發(fā)控制)實現(xiàn)的關(guān)鍵。
4.2、流程
關(guān)于undolog的流程如下圖所示:
4.3、日志結(jié)構(gòu)
關(guān)于undolog的日志結(jié)構(gòu)如下圖所示:
5、常見問題與優(yōu)化
1. binlog 導(dǎo)致磁盤空間不足
- 問題:binlog 無限增長,占用磁盤空間。
- 解決方案:
-- 查看 binlog 狀態(tài) SHOW VARIABLES LIKE 'expire_logs_days'; -- 設(shè)置自動清理(單位:天) SET GLOBAL expire_logs_days = 7;
2. redolog 刷盤性能問題
問題:innodb_flush_log_at_trx_commit=1
會降低性能。
優(yōu)化建議:
- 生產(chǎn)環(huán)境:保持默認(rèn)值
1
(保證數(shù)據(jù)安全)。 - 性能優(yōu)先場景:可設(shè)置為
2
(每秒刷盤一次,風(fēng)險略高)。
總結(jié)
MySQL中的binlog、redolog和undolog日志類型,包括它們的作用、格式和刷盤機制。binlog主要用于主從復(fù)制和數(shù)據(jù)恢復(fù),redolog確保事務(wù)的持久性,而undolog則實現(xiàn)了事務(wù)的原子性。
通過理解這些日志機制,可以更好地保障數(shù)據(jù)庫的安全性和性能。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
mysql問題之slow log中出現(xiàn)大量的binlog dump記錄的解決方法
今天在查看mysql中發(fā)現(xiàn)比較慢,然后我使用了slow log,發(fā)現(xiàn)出現(xiàn)了大量的binlog dump記錄,下面我來給大家整理一下這個問題的解決辦法2013-09-09mysql5.7的安裝及Navicate長久免費使用的實現(xiàn)過程
這篇文章主要介紹了mysql5.7的安裝及Navicate長久免費使用的實現(xiàn)過程,本文給大家分享問題及解決方法,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-11-11將 Ghost 從 SQLite3 數(shù)據(jù)庫遷移到 MySQL 數(shù)據(jù)庫
如果網(wǎng)站流量小,直接使用 Ghost 默認(rèn)的 SQLite 數(shù)據(jù)庫還是很方便的,能夠省去安裝、配置數(shù)據(jù)庫的繁瑣步驟。但是,隨著網(wǎng)站流量的增加, SQLite 就慢慢頂不住了,這時最好的選擇就是使用 MySQL 數(shù)據(jù)庫。2014-07-07