偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

MySQL核心揭秘:從查詢(xún)到修改,徹底理解 Undo Log、Redo Log、Binlog 與 ACID 的關(guān)系

數(shù)據(jù)庫(kù) MySQL
作為MySQL特有的二進(jìn)制日志,支持?jǐn)?shù)據(jù)復(fù)制和恢復(fù),進(jìn)一步增強(qiáng)了數(shù)據(jù)的持久性和系統(tǒng)的可擴(kuò)展性。理解和掌握這些日志機(jī)制,不僅有助于優(yōu)化數(shù)據(jù)庫(kù)性能,提升事務(wù)處理效率,還能在面對(duì)系統(tǒng)故障時(shí)快速進(jìn)行數(shù)據(jù)恢復(fù),確保業(yè)務(wù)的連續(xù)性和數(shù)據(jù)的安全性。

1.前言

在當(dāng)今數(shù)據(jù)驅(qū)動(dòng)的時(shí)代,數(shù)據(jù)庫(kù)系統(tǒng)作為信息存儲(chǔ)和管理的核心組件,其性能和可靠性直接影響著應(yīng)用的穩(wěn)定性和用戶(hù)體驗(yàn)。MySQL,作為最流行的開(kāi)源關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)之一,被廣泛應(yīng)用于各類(lèi)互聯(lián)網(wǎng)應(yīng)用中。然而,許多開(kāi)發(fā)者和數(shù)據(jù)庫(kù)管理員對(duì)其內(nèi)部機(jī)制知之甚少,特別是在事務(wù)處理和日志管理方面。

事務(wù)的ACID特性(原子性 Atomicity、一致性 Consistency、隔離性 Isolation 和持久性 Durability)是保障數(shù)據(jù)庫(kù)操作可靠性和數(shù)據(jù)一致性的關(guān)鍵。為了實(shí)現(xiàn)這些特性,MySQL引入了多種日志機(jī)制,其中Undo Log、Redo Log和 Binlog 扮演著至關(guān)重要的角色。這些日志不僅確保了事務(wù)的正確執(zhí)行和系統(tǒng)的高可用性,還為數(shù)據(jù)恢復(fù)和復(fù)制提供了堅(jiān)實(shí)的基礎(chǔ)。

本文將帶您深入探討MySQL中Undo Log、Redo Log和Binlog的核心機(jī)制,全面解析它們?nèi)绾螀f(xié)同工作以保障事務(wù)的ACID特性。從查詢(xún)優(yōu)化到數(shù)據(jù)修改,我們將揭示這些日志在實(shí)際應(yīng)用中的具體實(shí)現(xiàn)方式和作用機(jī)制,幫助您全面掌握MySQL事務(wù)管理的內(nèi)部原理,提升數(shù)據(jù)庫(kù)設(shè)計(jì)和運(yùn)維的能力。

2.MySQL的架構(gòu)

圖片圖片

從圖中可以看出,MySQL 的架構(gòu)可以大致劃分為四個(gè)層次:連接層、服務(wù)層、存儲(chǔ)引擎層和文件系統(tǒng)層。

  • 連接層:負(fù)責(zé)對(duì)來(lái)自客戶(hù)端的連接進(jìn)行權(quán)限驗(yàn)證,并將連接信息存入連接池中,方便后續(xù)的連接復(fù)用。
  • 服務(wù)層:主要負(fù)責(zé) SQL 語(yǔ)句的解析與優(yōu)化,還包括查詢(xún)緩存和 MySQL 內(nèi)置函數(shù)的實(shí)現(xiàn)。
  • 存儲(chǔ)引擎層:提供多種可插拔的存儲(chǔ)引擎,允許我們通過(guò)不同的引擎進(jìn)行數(shù)據(jù)的存取操作。存儲(chǔ)引擎使得 MySQL 能夠直接與硬盤(pán)上的數(shù)據(jù)和日志進(jìn)行交互,用戶(hù)可以根據(jù)需求選擇合適的引擎。
  • 文件系統(tǒng)層:這一層主要包括日志文件、數(shù)據(jù)文件及與 MySQL 相關(guān)的其他程序。在這四個(gè)層次中,服務(wù)層和存儲(chǔ)引擎層構(gòu)成了架構(gòu)的核心。服務(wù)層負(fù)責(zé)處理 MySQL 的核心邏輯,而存儲(chǔ)引擎層則直接負(fù)責(zé)數(shù)據(jù)的存取操作。

3.Server服務(wù)層的功能

3.1 查詢(xún)解析與優(yōu)化

  • 語(yǔ)法解析:將客戶(hù)端發(fā)送的 SQL 查詢(xún)轉(zhuǎn)化為可理解的內(nèi)部結(jié)構(gòu),檢查 SQL 語(yǔ)句是否符合 MySQL 語(yǔ)法規(guī)則。后續(xù)步驟的傳遞和處理就是基于這個(gè)結(jié)構(gòu)的。
  • 查詢(xún)重寫(xiě):服務(wù)層會(huì)將一些查詢(xún)優(yōu)化為等效的、執(zhí)行效率更高的形式。
  • 查詢(xún)優(yōu)化:MySQL 服務(wù)層有一個(gè)查詢(xún)優(yōu)化器,會(huì)基于數(shù)據(jù)統(tǒng)計(jì)信息,選擇最優(yōu)的執(zhí)行計(jì)劃。包括表的連接順序、索引的選擇等。

3.2 查詢(xún)緩存

MySQL 服務(wù)層可以將一些查詢(xún)的結(jié)果緩存起來(lái),尤其是頻繁執(zhí)行的查詢(xún)。如果客戶(hù)端請(qǐng)求的查詢(xún)已經(jīng)存在于緩存中,MySQL 可以直接從緩存中返回結(jié)果,而無(wú)需重新執(zhí)行查詢(xún)。但是緩存在生產(chǎn)環(huán)境一般是不開(kāi)啟的,除非經(jīng)常有SQL一模一樣的查詢(xún)。緩存嚴(yán)格要求2次SQL請(qǐng)求要完全一樣。SQL語(yǔ)句,連接的數(shù)據(jù)庫(kù),協(xié)議版本,字符集等因素不一樣,都會(huì)導(dǎo)致緩存失效。從8.0版本開(kāi)始,MySQL不在使用緩存。

3.3 SQL 執(zhí)行

在查詢(xún)解析和優(yōu)化之后,服務(wù)層負(fù)責(zé)將 SQL 語(yǔ)句執(zhí)行。服務(wù)層會(huì)將解析后的查詢(xún)計(jì)劃傳遞給存儲(chǔ)引擎層,存儲(chǔ)引擎負(fù)責(zé)實(shí)際的數(shù)據(jù)操作。

4.Server服務(wù)層的核心組件

MySQL服務(wù)層有三個(gè)核心組件,分別是解析器,優(yōu)化器,執(zhí)行器。每個(gè)組件在查詢(xún)的過(guò)程中分別代表著不同的角色,下面將分別介紹這三者的作用:

4.1 解析器

解析器是 SQL 查詢(xún)執(zhí)行的第一步,它的主要職責(zé)是將用戶(hù)發(fā)送的 SQL 語(yǔ)句解析成數(shù)據(jù)庫(kù)能夠理解和處理的內(nèi)部結(jié)構(gòu)。這個(gè)過(guò)程包括以下幾個(gè)子階段:

  • 詞法分析:解析器首先對(duì) SQL 語(yǔ)句進(jìn)行詞法分析。詞法分析的任務(wù)是將 SQL 語(yǔ)句拆分成一系列有意義的“單詞”或“標(biāo)記”(Tokens),例如:表名,列名,操作符,關(guān)鍵字等。這個(gè)階段的輸出是一個(gè)由標(biāo)記組成的列表,為后續(xù)的語(yǔ)法分析提供基礎(chǔ)。
  • 語(yǔ)法分析:語(yǔ)法分析的任務(wù)是根據(jù) SQL 語(yǔ)法規(guī)則將標(biāo)記組合成一個(gè)層次化的結(jié)構(gòu),通常是 解析樹(shù)(Parse Tree)抽象語(yǔ)法樹(shù)(Abstract Syntax Tree)。解析樹(shù)的每個(gè)節(jié)點(diǎn)代表了 SQL 語(yǔ)句的一個(gè)語(yǔ)法結(jié)構(gòu)單元。在這一階段,MySQL 會(huì)檢查 SQL 語(yǔ)句的語(yǔ)法是否正確,并生成語(yǔ)法樹(shù)。如果 SQL 語(yǔ)法不正確,解析器會(huì)報(bào)錯(cuò)并拒絕執(zhí)行。
  • 語(yǔ)義分析:語(yǔ)義分析主要是檢查 SQL 語(yǔ)句中的每個(gè)對(duì)象是否符合數(shù)據(jù)庫(kù)的實(shí)際情況。如表名、字段名是否存在,用戶(hù)是否對(duì)相關(guān)表和列擁有執(zhí)行權(quán)限,數(shù)據(jù)類(lèi)型是否匹配等。

解析器將 SQL 語(yǔ)句從文本形式轉(zhuǎn)化為數(shù)據(jù)庫(kù)可以理解的內(nèi)部表示。它完成了從詞法、語(yǔ)法到語(yǔ)義的分析,并確保 SQL 語(yǔ)句符合語(yǔ)法和語(yǔ)義規(guī)則。

4.2 優(yōu)化器

優(yōu)化器的主要任務(wù)是對(duì) SQL 查詢(xún)進(jìn)行優(yōu)化,生成一個(gè)最優(yōu)的執(zhí)行計(jì)劃,從而提高查詢(xún)性能。優(yōu)化器的工作基于查詢(xún)的解析樹(shù)和元數(shù)據(jù),它會(huì)嘗試在不同的查詢(xún)執(zhí)行策略中選擇效率最高的一個(gè)。

4.2.1 邏輯優(yōu)化

在這一階段,優(yōu)化器會(huì)進(jìn)行一些邏輯層面的優(yōu)化,主要目的是通過(guò)調(diào)整 SQL 語(yǔ)句的結(jié)構(gòu)來(lái)提高查詢(xún)效率。這些優(yōu)化包括:

  • 消除冗余的子查詢(xún):將某些子查詢(xún)轉(zhuǎn)換為連接或合并查詢(xún)。
  • 重寫(xiě)查詢(xún):比如將 OR 條件轉(zhuǎn)換為 UNION 操作。
  • 查詢(xún)合并:將多個(gè)查詢(xún)合并成一個(gè)查詢(xún)。
  • 移除不必要的操作:例如消除不需要的 ORDER BY 或 DISTINCT。

4.2.2 物理優(yōu)化

優(yōu)化器根據(jù)數(shù)據(jù)庫(kù)的具體執(zhí)行引擎、索引、統(tǒng)計(jì)信息等做出的決策。這個(gè)階段會(huì)根據(jù)優(yōu)化器評(píng)估的成本模型選擇合適的執(zhí)行計(jì)劃。具體的優(yōu)化措施包括:

  • 選擇合適的連接方式:比如選擇 Nested Loop Join、Hash Join 或 Sort Merge Join。
  • 選擇索引:通過(guò)選擇合適的索引來(lái)加速數(shù)據(jù)訪問(wèn)。
  • 選擇合適的排序方式:通過(guò)使用索引掃描或臨時(shí)表來(lái)避免全表掃描。

優(yōu)化器會(huì)使用基于成本的模型(Cost-Based Optimization)來(lái)評(píng)估每種查詢(xún)執(zhí)行計(jì)劃的成本,選擇成本最低的執(zhí)行計(jì)劃。其核心是通過(guò)計(jì)算不同執(zhí)行計(jì)劃的資源消耗(如 CPU 時(shí)間、I/O 操作等),并選出最優(yōu)的執(zhí)行策略。

優(yōu)化器的目標(biāo)是通過(guò)多種優(yōu)化策略來(lái)降低查詢(xún)的執(zhí)行成本,生成一個(gè)盡可能高效的執(zhí)行計(jì)劃。它在邏輯層面和物理層面對(duì) SQL 查詢(xún)進(jìn)行優(yōu)化,以減少查詢(xún)執(zhí)行所需的資源。

4.3 執(zhí)行器

執(zhí)行器是 SQL 查詢(xún)執(zhí)行過(guò)程的最后一步,負(fù)責(zé)根據(jù)優(yōu)化器生成的執(zhí)行計(jì)劃來(lái)實(shí)際執(zhí)行 SQL 查詢(xún),返回查詢(xún)結(jié)果或修改數(shù)據(jù)庫(kù)的狀態(tài)。

4.3.1 權(quán)限檢查

在執(zhí)行之前,執(zhí)行器會(huì)首先檢查用戶(hù)是否有權(quán)限執(zhí)行相應(yīng)的操作。如果沒(méi)有權(quán)限,則返回錯(cuò)誤信息。

4.3.2 執(zhí)行計(jì)劃的執(zhí)行

執(zhí)行器根據(jù)優(yōu)化器選擇的執(zhí)行計(jì)劃一步步執(zhí)行 SQL 操作。執(zhí)行器的主要工作包括:

  • 表掃描:根據(jù)查詢(xún)條件決定是否使用索引、是否全表掃描。
  • 連接操作:根據(jù)優(yōu)化器選擇的連接方式(如嵌套循環(huán)連接、哈希連接等)執(zhí)行表之間的數(shù)據(jù)合并。
  • 排序和聚合:執(zhí)行查詢(xún)中的 ORDER BY、GROUP BY 等操作。
  • 數(shù)據(jù)返回:查詢(xún)結(jié)果被返回給用戶(hù),修改操作則會(huì)提交事務(wù)。

4.3.3 事務(wù)管理

對(duì)于涉及數(shù)據(jù)修改的 SQL(如 INSERT、UPDATE、DELETE 等),執(zhí)行器還需要管理事務(wù)的提交和回滾操作,確保數(shù)據(jù)的一致性和持久性。這些操作會(huì)與 MySQL 的日志系統(tǒng)(Undo Log、Redo Log、Binlog) 密切交互,確保事務(wù)的 ACID 屬性。

執(zhí)行器根據(jù)優(yōu)化器生成的執(zhí)行計(jì)劃實(shí)際執(zhí)行 SQL 查詢(xún),完成數(shù)據(jù)操作,返回查詢(xún)結(jié)果或更新數(shù)據(jù)庫(kù)狀態(tài)。它是查詢(xún)執(zhí)行的最后環(huán)節(jié),直接與 MySQL 的存儲(chǔ)引擎進(jìn)行交互。

5.MySQL查詢(xún)語(yǔ)句的執(zhí)行過(guò)程

MySQL一條SQL語(yǔ)句的執(zhí)行過(guò)程可以大致分為以下幾個(gè)步驟:圖片

  • 首先,通過(guò)連接器,客戶(hù)端與MySQL服務(wù)器建立連接,并完成身份認(rèn)證和權(quán)限驗(yàn)證過(guò)程。在此過(guò)程中,客戶(hù)端需要提供用戶(hù)名和密碼以證明其合法性,服務(wù)器則會(huì)對(duì)這些信息進(jìn)行核對(duì)。
  • 檢查是否開(kāi)啟緩存。MySQL 8.0之前,Query Cache 確實(shí)會(huì)緩存完全相同的查詢(xún)結(jié)果,以便重復(fù)執(zhí)行相同查詢(xún)時(shí)直接返回緩存數(shù)據(jù)。然而,MySQL 8.0及以后版本已經(jīng)完全棄用Query Cache,因此在MySQL 8.0及更高版本中這一步驟不在適用。
  • MySQL的解析器會(huì)對(duì)查詢(xún)語(yǔ)句進(jìn)行解析,檢查語(yǔ)法是否正確,并將查詢(xún)語(yǔ)句轉(zhuǎn)換為內(nèi)部數(shù)據(jù)結(jié)構(gòu)。預(yù)處理器則會(huì)根據(jù)MySQL的規(guī)則進(jìn)一步檢查解析樹(shù)是否合法,如檢查數(shù)據(jù)表或數(shù)據(jù)列是否存在等。
  • 優(yōu)化器會(huì)根據(jù)查詢(xún)語(yǔ)句的結(jié)構(gòu)、表的統(tǒng)計(jì)信息等因素,生成多個(gè)可能的執(zhí)行計(jì)劃,并通過(guò)成本估算器選出最優(yōu)的執(zhí)行計(jì)劃。這一步旨在提高查詢(xún)效率,降低資源消耗。
  • 執(zhí)行器按照優(yōu)化器選擇的執(zhí)行計(jì)劃,調(diào)用存儲(chǔ)引擎的API來(lái)執(zhí)行查詢(xún)。存儲(chǔ)引擎負(fù)責(zé)實(shí)際的數(shù)據(jù)存儲(chǔ)和檢索,根據(jù)執(zhí)行器的請(qǐng)求,讀取或?qū)懭霐?shù)據(jù)。
  • 存儲(chǔ)引擎負(fù)責(zé)實(shí)際的數(shù)據(jù)存儲(chǔ)和檢索工作,根據(jù)執(zhí)行器的請(qǐng)求,讀取或?qū)懭霐?shù)據(jù)。
  • 如果開(kāi)啟了Query Cache且查詢(xún)結(jié)果能夠命中緩存,查詢(xún)結(jié)果會(huì)從緩存中直接返回。而如果沒(méi)有開(kāi)啟Query Cache或緩存沒(méi)有命中,MySQL會(huì)直接返回查詢(xún)結(jié)果。

6.MySQL修改語(yǔ)句的執(zhí)行過(guò)程

我們簡(jiǎn)單列舉一條SQL為例 update table set name=“張三” where id = 10。具體的還行流程如下圖:

圖片圖片

  • 找存儲(chǔ)引擎取到 id = 10 這一行記錄。
  • 根據(jù)主鍵索引樹(shù)找到這一行,如果 id = 10 這一行所在的數(shù)據(jù)頁(yè)本來(lái)就在內(nèi)存池(Buffer Pool)中,就直接返回給執(zhí)行器;否則,需要先從磁盤(pán)讀入內(nèi)存池,然后再返回。
  • 記錄Undo Log日志,對(duì)數(shù)據(jù)進(jìn)行備份,便于回滾。
  • 拿到存儲(chǔ)引擎返回的行記錄,把 name 字段設(shè)置為 “張三”,得到一行新的記錄,然后再調(diào)用存儲(chǔ)引擎的接口寫(xiě)入這行新記錄。
  • 將這行新數(shù)據(jù)更新到內(nèi)存中,同時(shí)將這個(gè)更新操作記錄到 Redo Log 里面,為 Redo Log 中的事務(wù)打上 prepare 標(biāo)識(shí)。然后告知執(zhí)行器執(zhí)行完成了,隨時(shí)可以提交事務(wù)。
  • 生成這個(gè)操作的 Binlog,并把 Binlog 寫(xiě)入磁盤(pán)。
  • 提交事務(wù)。
  • 把剛剛寫(xiě)入的 Redo Log 狀態(tài)改成提交(commit)狀態(tài),更新完成。

以上只是一個(gè)簡(jiǎn)單的case,方便我們能夠簡(jiǎn)單的熟悉流程。接下來(lái),我們對(duì)update過(guò)程中的全流程進(jìn)行梳理,具體的流程如下圖:

圖片圖片

  • 首先客戶(hù)端發(fā)送一條 SQL 語(yǔ)句到 Server 層的 SQL interface。
  • SQL interface 接到該請(qǐng)求后,先對(duì)該條語(yǔ)句進(jìn)行解析,驗(yàn)證權(quán)限是否匹配,也就是在我們上文中講到的執(zhí)行器中在執(zhí)行。
  • 驗(yàn)證通過(guò)以后,分析器會(huì)對(duì)該語(yǔ)句分析,是否語(yǔ)法有錯(cuò)誤等。
  • 接下來(lái)是優(yōu)化器生成相應(yīng)的執(zhí)行計(jì)劃,選擇最優(yōu)的執(zhí)行計(jì)劃,然后是執(zhí)行器根據(jù)執(zhí)行計(jì)劃執(zhí)行這條語(yǔ)句。
  • 執(zhí)行器從Buffer Pool中獲取數(shù)據(jù)頁(yè)的數(shù)據(jù),如果數(shù)據(jù)頁(yè)沒(méi)有,需要從磁盤(pán)中進(jìn)行加載。
  • 開(kāi)啟事務(wù),修改數(shù)據(jù)之前先記錄Undo Log,寫(xiě)入Buffer Pool的Undo Page。
  • 開(kāi)始更新數(shù)據(jù)頁(yè)中的記錄,被修改的數(shù)據(jù)頁(yè)稱(chēng)為臟頁(yè),修改會(huì)被記錄到內(nèi)存中的 Redo Log Buffer中,再刷盤(pán)到磁盤(pán)的Redo Log文件,此時(shí)事務(wù)是 perpare階段。
  • 這個(gè)時(shí)候更新就完成了,當(dāng)時(shí)臟頁(yè)不會(huì)立即寫(xiě)入磁盤(pán),而是由后臺(tái)線(xiàn)程完成,這里會(huì)用double write來(lái)保證臟頁(yè)刷盤(pán)的可靠性。
  • 通知Server層,可以正式提交數(shù)據(jù)了, 執(zhí)行器記錄Binlog cache,事務(wù)提交時(shí)才會(huì)將該事務(wù)中的Binlog刷新到磁盤(pán)中。
  • 這個(gè)時(shí)候Update語(yǔ)句完成了Buffer Pool中數(shù)據(jù)頁(yè)的修改、Undo Log、Redo Log緩存記錄,以及記錄Binlog cache緩存。
  • commit階段,這個(gè)階段是將Redo Log中事務(wù)狀態(tài)標(biāo)記為commit。
  • 此時(shí)Binlog和Redo Log都已經(jīng)寫(xiě)入磁盤(pán),如果觸發(fā)了刷新臟頁(yè)的操作,先把臟頁(yè)copy到double write buffer里,double write buffer 的內(nèi)存數(shù)據(jù)刷到磁盤(pán)中的共享表空間 ibdata,再刷到數(shù)據(jù)磁盤(pán)上數(shù)據(jù)文件 ibd。

以上就是修改語(yǔ)句的全部流程,可以看到,上圖中涉及刷盤(pán)的操作本初沒(méi)有詳細(xì)講解,接下來(lái),將結(jié)合三大日志,詳細(xì)講解刷盤(pán)相關(guān)操作。

7.Undo Log、Redo Log和Binlog日志實(shí)現(xiàn)事務(wù)的ACID特性

7.1 事務(wù)的ACID特性概述

在深入理解Undo Log、Redo Log和Binlog之前,首先需要明確事務(wù)的ACID特性,這些特性是確保數(shù)據(jù)庫(kù)操作可靠性和一致性的基石。

  • 原子性(Atomicity):事務(wù)中的所有操作要么全部成功,要么全部失敗,不會(huì)出現(xiàn)部分完成的狀態(tài)。
  • 一致性(Consistency):事務(wù)的執(zhí)行必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)轉(zhuǎn)變到另一個(gè)一致性狀態(tài),確保數(shù)據(jù)的完整性。
  • 隔離性(Isolation):指在多事務(wù)并發(fā)執(zhí)行時(shí),一個(gè)事務(wù)的操作對(duì)其他事務(wù)的影響程度。它確保事務(wù)之間的操作是相互獨(dú)立的,避免并發(fā)帶來(lái)的數(shù)據(jù)不一致問(wèn)題。
  • 持久性(Durability):一旦事務(wù)提交,其對(duì)數(shù)據(jù)庫(kù)的修改是永久性的,即使系統(tǒng)發(fā)生故障也不會(huì)丟失。

7.2 Undo Log(回滾日志)

Undo Log記錄了事務(wù)在修改數(shù)據(jù)之前的原始狀態(tài),用于在事務(wù)回滾時(shí)撤銷(xiāo)未完成的修改,確保事務(wù)的原子性和隔離性。

Undo Log主要的功能有兩個(gè):事務(wù)回滾和MVCC。

首先來(lái)說(shuō)事務(wù)回滾,事務(wù)如何通過(guò)Undo Log進(jìn)行回滾操作呢?其實(shí)很簡(jiǎn)單,只需要在Undo Log日志中記錄事務(wù)中的反向操作即可,發(fā)生回滾時(shí)直接通過(guò)Undo Log中記錄的反向操作進(jìn)行恢復(fù)。例如:

  • 事務(wù)進(jìn)行insert操作,Undo Log記錄delete操作。
  • 事務(wù)進(jìn)行delete操作,Undo Log記錄insert操作。
  • 事務(wù)進(jìn)行update操作(value1 改為value2 ),Undo Log記錄update操作(value2 改為value1 )。

Undo Log 保存的是一個(gè)版本的鏈路,使用roll_pointer這個(gè)字段來(lái)連接的。多個(gè)事務(wù)的Undo Log 日志組成了一個(gè)版本鏈,如圖:

圖片圖片

在上圖中:

  • trx_id代表事務(wù)id,記錄了這一系列事務(wù)操作是基于哪個(gè)事務(wù)。
  • roll_pointer代表回滾指針,就是當(dāng)要發(fā)生rollback回滾操作時(shí),就通過(guò)roll_pointer進(jìn)行回滾,這個(gè)鏈表稱(chēng)為版本鏈。在事務(wù)執(zhí)行過(guò)程中,如果發(fā)生錯(cuò)誤或主動(dòng)回滾,Undo Log 會(huì)將數(shù)據(jù)恢復(fù)到事務(wù)開(kāi)始前的狀態(tài),確保事務(wù)的所有操作要么全部完成,要么全部撤銷(xiāo),從而實(shí)現(xiàn)原子性。

為了 提升 Undo Log 讀寫(xiě)性能, Undo頁(yè)還存在于Buffer Pool中,因?yàn)锽uffer Pool 是 InnoDB 的內(nèi)存緩存,用于存儲(chǔ)數(shù)據(jù)頁(yè)和索引頁(yè),以便快速訪問(wèn)。它通過(guò)減少磁盤(pán) I/O,提高數(shù)據(jù)庫(kù)的整體性能。將Undo頁(yè)放在緩存中,可以加速事務(wù)的回滾和數(shù)據(jù)恢復(fù)。

當(dāng)事務(wù)commit之后,不會(huì)立即刪除,會(huì)保留至所有快照讀完成。后續(xù)會(huì)通過(guò)后臺(tái)線(xiàn)程中的Master Thread或Purge Thread進(jìn)行Undo Page的回收工作。

再說(shuō)MVCC,實(shí)現(xiàn)了自己 Copy-On-Write思想提升并發(fā)能力的時(shí)候, 也需要數(shù)據(jù)的副本,如上圖,既然已經(jīng)存在了這么多Undo Log的副本,那么MVCC可以直接復(fù)用這些副本數(shù)據(jù)。

所以,Undo Log中的副本,可以用于實(shí)現(xiàn)多版本并發(fā)控制(MVCC),提升事務(wù)的并發(fā)性能,同時(shí)每一個(gè)事務(wù)操作自己的副本,實(shí)現(xiàn)事務(wù)的隔離性。

實(shí)現(xiàn)MVCC主要通過(guò)三個(gè)元素,一個(gè)是我們上面已經(jīng)提到的Undo Log版本鏈,一個(gè)是readView,最后就是我們上面已經(jīng)提到的這些字段。因?yàn)檎麄€(gè)課題比較大,在這里就不在過(guò)多的贅述。

7.3 Redo Log(重做日志)

Redo Log記錄了事務(wù)對(duì)數(shù)據(jù)的修改操作,用于在系統(tǒng)崩潰后恢復(fù)已提交事務(wù)的修改,確保事務(wù)的持久性。

7.3.1 Redo Log 日志執(zhí)行過(guò)程

當(dāng)一個(gè)更新事務(wù)到達(dá)時(shí),Redo Log的處理過(guò)程如下:

  • 首先,從磁盤(pán)讀取原始數(shù)據(jù)到Buffer Pool(內(nèi)存中),然后在內(nèi)存中對(duì)數(shù)據(jù)進(jìn)行修改,修改后的數(shù)據(jù)將被標(biāo)記為臟頁(yè)。
  • 接著,系統(tǒng)會(huì)生成一系列重做日志,并將其寫(xiě)入Redo Log Buffer,日志內(nèi)容記錄的是數(shù)據(jù)修改后的新值。
  • 當(dāng)事務(wù)提交(commit)時(shí),Redo Log Buffer中的內(nèi)容會(huì)被刷新到Redo Log File中,并采用追加寫(xiě)的方式將日志記錄寫(xiě)入文件。
  • 定期會(huì)將內(nèi)存中修改過(guò)的數(shù)據(jù)刷新回磁盤(pán),以保證數(shù)據(jù)持久性。

Redo Log利用WAL(Write-Ahead Logging)機(jī)制來(lái)保證故障恢復(fù)的安全性(crash-safe)。

WAL的核心思想是先寫(xiě)日志,再寫(xiě)磁盤(pán)。根本原因是機(jī)械磁盤(pán)的性能,日志是順序?qū)?,而?shù)據(jù)頁(yè)是隨機(jī)寫(xiě)。順序?qū)懙男阅芨?,所以先把日志歸檔。具體來(lái)說(shuō),當(dāng)緩存頁(yè)被修改(即變成臟頁(yè))后,相關(guān)的操作會(huì)先記錄到Redo Log Buffer中。在事務(wù)提交(commit)時(shí),后臺(tái)線(xiàn)程會(huì)將Redo Log Buffer中的內(nèi)容刷新到磁盤(pán)上(事務(wù)提交是Redo Log默認(rèn)刷盤(pán)的時(shí)機(jī))。此時(shí),雖然臟頁(yè)還沒(méi)有寫(xiě)回磁盤(pán),但只要Redo Log成功寫(xiě)入磁盤(pán),就可以認(rèn)為此次修改操作已完成。這是因?yàn)?,即使發(fā)生故障導(dǎo)致臟頁(yè)丟失,我們也可以通過(guò)磁盤(pán)上的Redo Log來(lái)恢復(fù)數(shù)據(jù)。因此,Redo Log與Undo Log的配合作用如下:

  • 若事務(wù)在提交前發(fā)生崩潰,則可以通過(guò)Undo Log回滾事務(wù)。
  • 若事務(wù)在提交后發(fā)生崩潰,則可以通過(guò)Redo Log來(lái)恢復(fù)事務(wù)。

7.3.2 Redo Log日志文件寫(xiě)入機(jī)制

Redo Log采用固定大小并循環(huán)寫(xiě)入的方式,類(lèi)似環(huán)形緩沖區(qū)。當(dāng)日志文件寫(xiě)滿(mǎn)時(shí),會(huì)從頭開(kāi)始覆蓋之前的內(nèi)容。這樣的設(shè)計(jì)是因?yàn)镽edo Log記錄的是數(shù)據(jù)頁(yè)的修改,而一旦Buffer Pool中的數(shù)據(jù)頁(yè)被刷寫(xiě)到磁盤(pán),之前的Redo Log記錄就不在有效。新的日志會(huì)覆蓋這些過(guò)時(shí)的記錄。此外,硬盤(pán)上的Redo Log文件并非單一存在,而是以文件組的形式存儲(chǔ),每個(gè)文件的大小都相同。

圖片圖片

在寫(xiě)入數(shù)據(jù)的同時(shí),也需要執(zhí)行擦除操作。Redo Log成功刷盤(pán)到磁盤(pán)后,才可以進(jìn)行擦除。因此,我們使用兩個(gè)指針來(lái)管理這一過(guò)程:

  • write pos:表示當(dāng)前日志記錄寫(xiě)入的位置,即當(dāng)前Redo Log文件已寫(xiě)到哪里。
  • checkpoint:表示當(dāng)前可以擦除的位置,即Redo Log文件中哪些記錄已不在需要,可以被新的日志覆蓋。

圖片圖片

在圖示中,黃色部分表示已寫(xiě)入完成的區(qū)域,而綠色部分則代表空閑區(qū)域。

write pos和checkpoint指針之間的綠色區(qū)域,表示剩余的可寫(xiě)入空間,即Redo Log文件的空閑/可用部分。

當(dāng)進(jìn)行數(shù)據(jù)頁(yè)刷盤(pán)操作(checkpoint)時(shí),checkpoint指針會(huì)順時(shí)針移動(dòng),覆蓋掉已寫(xiě)入的黃色區(qū)域,使其變?yōu)榫G色。

當(dāng)write pos追趕上checkpoint時(shí),意味著Redo Log文件已滿(mǎn),此時(shí)必須強(qiáng)制執(zhí)行checkpoint操作,刷新Buffer Pool中的臟頁(yè)并將其寫(xiě)入磁盤(pán)。隨后,checkpoint指針會(huì)被移動(dòng),這樣就可以繼續(xù)向Redo Log文件中寫(xiě)入新的數(shù)據(jù)。

7.3.3 Redo Log Buffer刷盤(pán)策略

Redo Log Buffer刷盤(pán)策略主分為三種,由核心參數(shù)innodb_flush_log_at_trx_commit來(lái)控制。具體的流程如同下圖:

圖片圖片

  • innodb_flush_log_at_trx_commit=0

刷盤(pán)時(shí)機(jī):InnoDB每秒鐘會(huì)將日志緩存(Redo Log Buffer)刷新到磁盤(pán),而不是在每次事務(wù)提交時(shí)進(jìn)行刷新。即便事務(wù)已提交,日志僅會(huì)寫(xiě)入內(nèi)存中的日志緩沖區(qū),1秒鐘后由后臺(tái)線(xiàn)程將其寫(xiě)入磁盤(pán)。

持久性:如果發(fā)生數(shù)據(jù)庫(kù)崩潰,可能會(huì)丟失最近1秒內(nèi)的事務(wù)數(shù)據(jù)。

性能:這種方式提供最高的性能,因?yàn)榇疟P(pán)寫(xiě)入的頻率最小,但相應(yīng)的持久性較弱。

圖片圖片

  • innodb_flush_log_at_trx_commit=1(默認(rèn)設(shè)置)

當(dāng)設(shè)置為1時(shí),表示每次事務(wù)提交時(shí),都會(huì)執(zhí)行刷盤(pán)操作。這意味著在默認(rèn)配置下,系統(tǒng)提供高可靠性,但性能較低。

刷盤(pán)時(shí)機(jī):每當(dāng)事務(wù)提交時(shí),InnoDB會(huì)將日志緩沖區(qū)的內(nèi)容寫(xiě)入到文件系統(tǒng)緩存中,并立即使用fsync將其刷新到磁盤(pán)。

持久性:這種設(shè)置提供了最高級(jí)別的持久性,確保每次事務(wù)提交后日志已持久化到磁盤(pán)。如果發(fā)生崩潰,最多會(huì)丟失尚未提交的事務(wù)。

性能:性能較差,因?yàn)槊看问聞?wù)提交都需要進(jìn)行磁盤(pán)寫(xiě)入操作。在高并發(fā)寫(xiě)入的環(huán)境中,頻繁的磁盤(pán)I/O可能會(huì)成為系統(tǒng)的性能瓶頸。

  • innodb_flush_log_at_trx_commit=2

當(dāng)設(shè)置為2時(shí),表示每次事務(wù)提交時(shí),InnoDB僅將Redo Log緩沖區(qū)的內(nèi)容寫(xiě)入操作系統(tǒng)的文件系統(tǒng)緩存(Page Cache),而實(shí)際的磁盤(pán)刷盤(pán)操作由操作系統(tǒng)來(lái)負(fù)責(zé)。

刷盤(pán)時(shí)機(jī):在每次事務(wù)提交時(shí),InnoDB會(huì)將日志緩沖區(qū)的內(nèi)容寫(xiě)入操作系統(tǒng)的文件系統(tǒng)緩存(Page Cache),此時(shí)并不會(huì)執(zhí)行fsync操作,日志的實(shí)際寫(xiě)入磁盤(pán)由操作系統(tǒng)決定。

持久性:如果數(shù)據(jù)庫(kù)發(fā)生崩潰,但服務(wù)器沒(méi)有崩潰,數(shù)據(jù)不會(huì)丟失。如果服務(wù)器也發(fā)生崩潰,Page Cache默認(rèn)保留最近5秒的數(shù)據(jù),最多丟失最近5秒內(nèi)的事務(wù)。但與innodb_flush_log_at_trx_commit=0不同,日志至少會(huì)寫(xiě)入文件系統(tǒng)緩存,這為數(shù)據(jù)安全性提供了一定保障。

性能:性能較高,因?yàn)槊看问聞?wù)提交時(shí),只需將日志寫(xiě)入操作系統(tǒng)的內(nèi)存緩存,而不需要立即執(zhí)行磁盤(pán)I/O操作,從而減少了磁盤(pán)操作的頻率。

以上三種策略中:

  • 如果是對(duì)數(shù)據(jù)安全性要求比較高的場(chǎng)景,則需要將參數(shù)設(shè)置為1,因?yàn)?的安全性最高。
  • 如果是在一些可以容忍數(shù)據(jù)庫(kù)崩潰時(shí)丟失 1s 數(shù)據(jù)的場(chǎng)景,我們可以將該值設(shè)置為 0,這樣可以明顯地減少日志同步到磁盤(pán)的 I/O 操作。
  • 如果是需要安全性和性能折中的方案,可以將參數(shù)設(shè)置為2,雖然參數(shù) 2 沒(méi)有參數(shù) 0 的性能高,但是數(shù)據(jù)安全性方面比參數(shù) 0 強(qiáng),因?yàn)閰?shù) 2 只要操作系統(tǒng)不宕機(jī),即使數(shù)據(jù)庫(kù)崩潰了,也不會(huì)丟失數(shù)據(jù),同時(shí)性能方便比參數(shù) 1 高。

7.4 Binlog(二進(jìn)制日志)

Binlog是MySQL特有的一種日志機(jī)制,記錄了所有導(dǎo)致數(shù)據(jù)庫(kù)狀態(tài)變化的操作(如INSERT、UPDATE、DELETE)。Binlog主要有兩個(gè)功能:

  • 備份恢復(fù),實(shí)現(xiàn)崩潰一致性(Crash Consistency)。原理是每次事務(wù)進(jìn)行提交時(shí),都會(huì)將增、刪、改操作以追加的方式記錄到Binlog文件中。
  • 主從復(fù)制,實(shí)現(xiàn) 主從復(fù)制的一致性。原理是主從復(fù)制常用于MySQL主從集群搭建,MySQL從節(jié)點(diǎn)通過(guò)監(jiān)聽(tīng)主節(jié)點(diǎn)Binlog日志進(jìn)行同步即可。

7.4.1 Binlog的刷盤(pán)時(shí)機(jī)

事務(wù)執(zhí)行過(guò)程中,先把日志寫(xiě)到 Binlog Cache(Server 層的 Cache),事務(wù)提交的時(shí)候,再把 Binlog Cache 寫(xiě)到 Binlog 文件中。由于一個(gè)事務(wù)的Binlog日志必須作為一個(gè)整體寫(xiě)入,不能拆分,不論事務(wù)多大,都會(huì)確保日志在一次操作中完整寫(xiě)入。因此,系統(tǒng)為每個(gè)線(xiàn)程分配了一個(gè)塊內(nèi)存用于存儲(chǔ)Binlog Cache。盡管每個(gè)線(xiàn)程有自己的Binlog Cache,最終這些日志都會(huì)寫(xiě)入到同一個(gè)Binlog文件中。

圖片圖片

  • 圖中的 write,指的就是指把日志寫(xiě)入到 Page Cache ,但是并沒(méi)有把數(shù)據(jù)持久化到磁盤(pán),因?yàn)閿?shù)據(jù)還緩存在文件系統(tǒng)的 Page Cache 里,write 的寫(xiě)入速度還是比較快的,因?yàn)椴簧婕按疟P(pán) I/O。
  • 圖中的 fsync,才是將數(shù)據(jù)持久化到磁盤(pán)的操作,這里就會(huì)涉及磁盤(pán) I/O,所以頻繁的 fsync 會(huì)導(dǎo)致磁盤(pán)的 I/O 升高。

MySQL提供了一個(gè)sync_binlog參數(shù),用于控制Binlog日志寫(xiě)入磁盤(pán)的頻率:

  • sync_binlog = 0:每次事務(wù)提交時(shí),只進(jìn)行寫(xiě)操作(write),不執(zhí)行fsync,具體何時(shí)將數(shù)據(jù)持久化到磁盤(pán)由操作系統(tǒng)決定。
  • sync_binlog = 1:每次事務(wù)提交時(shí),先進(jìn)行寫(xiě)操作(write),然后立即執(zhí)行fsync,確保日志被持久化到磁盤(pán)。
  • sync_binlog = N(N > 1):每次事務(wù)提交時(shí)只執(zhí)行寫(xiě)操作(write),但累積N個(gè)事務(wù)后才會(huì)執(zhí)行fsync,將日志持久化到磁盤(pán)。在MySQL中,默認(rèn)的sync_binlog設(shè)置為0,意味著沒(méi)有強(qiáng)制性的磁盤(pán)刷新操作,這樣可以獲得最佳的性能,但也伴隨較高的風(fēng)險(xiǎn)。如果操作系統(tǒng)發(fā)生異常重啟,尚未持久化到磁盤(pán)的Binlog數(shù)據(jù)將會(huì)丟失。

當(dāng)sync_binlog設(shè)置為1時(shí),系統(tǒng)提供最強(qiáng)的安全性,確保即使發(fā)生異常重啟,也最多丟失一個(gè)事務(wù)的Binlog,而已經(jīng)持久化的數(shù)據(jù)不會(huì)受到影響。然而,這種設(shè)置對(duì)性能的影響非常大。

如果能夠接受少量事務(wù)Binlog丟失的風(fēng)險(xiǎn),并希望提高寫(xiě)入性能,一般可以將sync_binlog設(shè)置為100到1000之間的某個(gè)值,從而在性能和安全性之間找到平衡。

8 總結(jié)

通過(guò)本文的深入解析,我們?nèi)媪私饬薓ySQL中Undo Log、Redo Log和Binlog三大日志機(jī)制,以及它們?cè)诒U鲜聞?wù)ACID特性中的關(guān)鍵作用。

  • Undo Log:通過(guò)記錄數(shù)據(jù)修改前的狀態(tài),確保事務(wù)在發(fā)生錯(cuò)誤或回滾時(shí)能夠恢復(fù)到初始狀態(tài),保障了原子性和隔離性。
  • Redo Log:通過(guò)記錄事務(wù)的修改操作,確保即使在系統(tǒng)崩潰后,已提交的事務(wù)也能被恢復(fù),保障了持久性。
  • Binlog:作為MySQL特有的二進(jìn)制日志,支持?jǐn)?shù)據(jù)復(fù)制和恢復(fù),進(jìn)一步增強(qiáng)了數(shù)據(jù)的持久性和系統(tǒng)的可擴(kuò)展性。理解和掌握這些日志機(jī)制,不僅有助于優(yōu)化數(shù)據(jù)庫(kù)性能,提升事務(wù)處理效率,還能在面對(duì)系統(tǒng)故障時(shí)快速進(jìn)行數(shù)據(jù)恢復(fù),確保業(yè)務(wù)的連續(xù)性和數(shù)據(jù)的安全性。同時(shí),這些知識(shí)也為構(gòu)建高可用、高性能的數(shù)據(jù)庫(kù)架構(gòu)提供了堅(jiān)實(shí)的理論基礎(chǔ)。

在實(shí)際應(yīng)用中,合理配置和管理這些日志機(jī)制,結(jié)合具體業(yè)務(wù)需求進(jìn)行優(yōu)化,是每位數(shù)據(jù)庫(kù)管理員和開(kāi)發(fā)者需要掌握的重要技能。希望通過(guò)本文,您能夠?qū)ySQL的核心機(jī)制有更深刻的理解,并在實(shí)際工作中靈活運(yùn)用,為構(gòu)建穩(wěn)定可靠的數(shù)據(jù)庫(kù)系統(tǒng)貢獻(xiàn)力量。

關(guān)于作者:朱洪旭 俠客匯Java開(kāi)發(fā)工程師

參考資料

[1] 《MySQL實(shí)戰(zhàn)45講》

[2] https://zhuanlan.zhihu.com/p/451007506

[3] https://zhuanlan.zhihu.com/p/667283776

責(zé)任編輯:武曉燕 來(lái)源: 轉(zhuǎn)轉(zhuǎn)技術(shù)
相關(guān)推薦

2025-01-15 13:19:09

MySQL日志事務(wù)

2020-08-20 12:10:42

MySQL日志數(shù)據(jù)庫(kù)

2024-05-28 00:10:00

JavaMySQL數(shù)據(jù)庫(kù)

2024-05-30 08:03:17

2025-06-06 07:02:43

2024-06-11 00:00:02

MySQL數(shù)據(jù)庫(kù)系統(tǒng)

2023-11-23 13:17:39

MySQL?數(shù)據(jù)庫(kù)

2021-01-26 13:47:08

MySQL存儲(chǔ)數(shù)據(jù)

2024-03-14 14:18:58

MySQL業(yè)務(wù)設(shè)計(jì)事務(wù)

2025-01-20 08:20:00

redo logMySQL數(shù)據(jù)庫(kù)

2021-02-09 10:07:23

面試MySQL存儲(chǔ)

2025-08-11 09:08:41

2025-10-09 02:22:00

MySQLMVCC庫(kù)存數(shù)量

2021-07-28 08:32:03

MySQLRedo存儲(chǔ)

2021-10-04 09:23:30

Redo日志內(nèi)存

2021-05-28 11:18:50

MySQLbin logredo log

2020-11-11 07:32:18

MySQL InnoDB 存儲(chǔ)

2025-08-29 07:58:42

2010-01-06 09:30:51

Oracle Redo

2018-07-31 16:10:51

Redo Undo數(shù)據(jù)庫(kù)數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)