「MySQL系列」InnoDB的架構(gòu)和原理深入刨析
一 存儲(chǔ)引擎體系
1.1 MySQL體系架構(gòu)

上圖描述
- Connection Pool : 連接池組件
- Management Services & Utilities : 管理服務(wù)和工具組件
- SQL Interface : SQL接口組件
- Parser : 查詢分析器組件
- Optimizer : 優(yōu)化器組件
- Caches & Buffers : 緩沖池組件
- Pluggable Storage Engines : 存儲(chǔ)引擎
- File System : 文件系統(tǒng)
1. 連接層
- 最上層是一些客戶端和鏈接服務(wù),包含本地sock 通信和大多數(shù)基于客戶端/服務(wù)端工具實(shí)現(xiàn)的類似于TCP/IP的通信。主要完成一些類似于連接處理、授權(quán)認(rèn)證、及相關(guān)的安全方案。在該層上引入了線程池的概念,為通過認(rèn)證安全接入的客戶端提供線程。同樣在該層上可以實(shí)現(xiàn)基于SSL的安全鏈接。服務(wù)器也會(huì)為安全接入的每個(gè)客戶端驗(yàn)證它所具有的操作權(quán)限。
2. 服務(wù)層
- 第二層架構(gòu)主要完成大多數(shù)的核心服務(wù)功能,如SQL接口,并完成緩存的查詢,SQL的分析和優(yōu)化,部分內(nèi)置函數(shù)的執(zhí)行。所有跨存儲(chǔ)引擎的功能也在這一層實(shí)現(xiàn),如 過程、函數(shù)等。在該層,服務(wù)器會(huì)解析查詢并創(chuàng)建相應(yīng)的內(nèi)部解析樹,并對其完成相應(yīng)的優(yōu)化如確定表的查詢的順序,是否利用索引等,最后生成相應(yīng)的執(zhí)行操作。如果是select語句,服務(wù)器還會(huì)查詢內(nèi)部的緩存,如果緩存空間足夠大,這樣在解決大量讀操作的環(huán)境中能夠很好的提升系統(tǒng)的性能。
3. 引擎層
- 存儲(chǔ)引擎層, 存儲(chǔ)引擎真正的負(fù)責(zé)了MySQL中數(shù)據(jù)的存儲(chǔ)和提取,服務(wù)器通過API和存儲(chǔ)引擎進(jìn)行通信。不同的存儲(chǔ)引擎具有不同的功能,這樣我們可以根據(jù)自己的需要,來選取合適的存儲(chǔ)引擎。
4. 存儲(chǔ)層
數(shù)據(jù)存儲(chǔ)層, 主要是將數(shù)據(jù)存儲(chǔ)在文件系統(tǒng)之上,并完成與存儲(chǔ)引擎的交互。
和其他數(shù)據(jù)庫相比,MySQL存儲(chǔ)引擎是插件式的存儲(chǔ)引擎架構(gòu)。將 查詢處理和其他的系統(tǒng)任務(wù)以及數(shù)據(jù)的存儲(chǔ)提取分離。這種架構(gòu)可 以根據(jù)業(yè)務(wù)的需求和實(shí)際需要選擇合適的存儲(chǔ)引擎。
1.2 存儲(chǔ)引擎介紹
1. 概述
針對不同的存儲(chǔ)需求可以選擇最優(yōu)的存儲(chǔ)引擎。存儲(chǔ)引擎就是存 儲(chǔ)數(shù)據(jù),建立索引,更新查詢數(shù)據(jù)等等技術(shù)的實(shí)現(xiàn)方式 。存儲(chǔ)引 擎是基于表的,而不是基于庫的。所以存儲(chǔ)引擎也可被稱為表類 型。
2. 查看MySQL存儲(chǔ)引擎

3. MySQL常見兩種引擎

MySQL默認(rèn)支持InnoDB
二 InnoDB深入刨析
2.1 InnoDB體系結(jié)構(gòu)

1. 緩沖池
介紹
InnoDB存儲(chǔ)引擎基于磁盤文件存儲(chǔ),訪問物理硬盤和在內(nèi)存中進(jìn)行訪問,速度相差很大,為了盡可能 彌補(bǔ)這兩者之間的I/O效率的差值,就需要把經(jīng)常使用的數(shù)據(jù)加載到緩沖池中,避免每次訪問都進(jìn)行磁 盤I/O。
在InnoDB的緩沖池中不僅緩存了索引頁和數(shù)據(jù)頁,還包含了undo頁、插入緩存、自適應(yīng)哈希索引以及 InnoDB的鎖信息等等。
讀取
在數(shù)據(jù)庫中進(jìn)行讀取頁的操作時(shí), 首先將磁盤中讀取到的頁數(shù)據(jù)存放在緩沖池中, 下一次再讀相同的 頁時(shí), 首先判斷緩沖池中是否存在,如果緩沖池被命中,則直接讀取數(shù)據(jù), 如果沒有,則讀取磁盤中 的頁數(shù)據(jù)。
更新
而對于數(shù)據(jù)庫中頁的修改操作,則首先修改在緩沖池中的頁,然后再以一定的頻率刷新到磁盤上,從而 保證緩沖池中的數(shù)據(jù)與磁盤中的數(shù)據(jù)一致。頁從緩沖池刷新回磁盤的操作并不是在每次頁發(fā)生更新時(shí), 都需要觸發(fā),出于整體的性能考慮,而是通過checkpoint機(jī)制刷新回磁盤。
參數(shù)配置
在專用服務(wù)器上,通常將多達(dá)80%的物理內(nèi)存分配給緩沖池。參數(shù)設(shè)置:
- show variables like 'innodb_buffer_pool_size';
在InnoDB引擎中,允許有多個(gè)緩沖池實(shí)例,根據(jù)頁的哈希值分配到不同的緩沖池實(shí)例中,從而減少數(shù) 據(jù)庫內(nèi)部的資源競爭, 提升并發(fā)處理能力。參數(shù)配置:

- vi /etc/my.conf
- innodb_buffer_pool_size=268435456
2. 后臺(tái)線程
Master Thread
主要負(fù)責(zé)將緩沖池中的數(shù)據(jù)異步刷新到磁盤中, 保持?jǐn)?shù)據(jù)的一致性, 還包括臟頁的刷新、合并插入緩 存、undo頁的回收 。
IO Thread
在InnoDB存儲(chǔ)引擎中大量使用了AIO來處理IO請求, 這樣可以極大地提高數(shù)據(jù)庫的性能,而IO Thread主要負(fù)責(zé)這些IO請求的回調(diào)。


Purge Thread
主要用于回收事務(wù)已經(jīng)提交了的undo log,在事務(wù)提交之后,undo log可能不用了,就用它來回 收。

Pager Cleaner Thread
新引入的一個(gè)用于協(xié)助 Master Thread 刷新臟頁到磁盤的線程,它可以減輕 Master Thread 的 工作壓力,減少阻塞。
3. 文件
frm文件
該文件是用來保存每個(gè)表的元數(shù)據(jù)信息的, 主要包含表結(jié)構(gòu)定義 。
系統(tǒng)表空間
系統(tǒng)表空間是InnoDB數(shù)據(jù)字典,二次寫緩沖區(qū),更改緩沖區(qū)和撤消日志的存儲(chǔ)區(qū) 。系統(tǒng)表空間可以具 有一個(gè)或多個(gè)數(shù)據(jù)文件, 默認(rèn)情況下會(huì)在數(shù)據(jù)存放目錄中創(chuàng)建一個(gè)名為 ibdata1 表空間數(shù)據(jù)文件。該文件名稱可以通過參數(shù) innodb_data_file_path 指定。

- file_name:file_size[:autoextend[:max:max_file_size]]
獨(dú)占表空間
innodb中設(shè)置了參數(shù) innodb_file_per_table 為 1/ON,則會(huì)將存儲(chǔ)的數(shù)據(jù)、索引等信息單獨(dú) 存儲(chǔ)在一個(gè)獨(dú)占表空間,因此也會(huì)產(chǎn)生一個(gè)獨(dú)占表空間文件(ibd)
redo log
重做日志, 用于恢復(fù)提交事務(wù)修改的頁操作 , 用來保證事務(wù)的原子性和持久性。主要是解決 提交 的事務(wù)沒有執(zhí)行完成但是數(shù)據(jù)庫崩潰了,當(dāng)數(shù)據(jù)庫恢復(fù)之后,可以完整的恢復(fù)數(shù)據(jù)。在執(zhí)行操作時(shí), InnoDB存儲(chǔ)引擎會(huì)首先將重做日志信息放到這個(gè)緩沖區(qū) redo log buffer,然后按照不同的策略和 頻率將buffer中的數(shù)據(jù)刷新到重做日志中。redo log在磁盤中保存的名稱為 ib_logfile0,ib_logfile1。
bin log
二進(jìn)制日志,其中記錄表結(jié)構(gòu)中的數(shù)據(jù)變更,包含DDL與DML。
其他
錯(cuò)誤日志、查詢?nèi)罩?、慢查詢?nèi)罩镜取?/p>
2.2 InnoDB邏輯存儲(chǔ)結(jié)構(gòu)

1. 表空間
表空間是InnoDB存儲(chǔ)引擎邏輯結(jié)構(gòu)的最高層, 大部分?jǐn)?shù)據(jù)都存在于共享表空間ibdata1中。如果用 戶啟用了參數(shù) innodb_file_per_table ,則每張表都會(huì)有一個(gè)表空間(xxx.ibd),里面存放表 中的數(shù)據(jù)、索引和插入緩存Bitmap頁。其他的數(shù)據(jù)如undo log、插入緩存索引頁、系統(tǒng)事務(wù)信息、 二次寫緩存都是在共享表空間中。
2. 段
表空間是由各個(gè)段組成的,常見的段有數(shù)據(jù)段、索引段、回滾段等。InnoDB存儲(chǔ)引擎是基于索引組織 的,因此數(shù)據(jù)即是索引,索引即數(shù)據(jù)。數(shù)據(jù)段就是B+樹的葉子節(jié)點(diǎn), 索引段即為B+樹的非葉子節(jié)點(diǎn)。InnoDB中對于段的管理,都是引擎自身完成,不需要人為對其控制。
3. 區(qū)
區(qū)是表空間的單元結(jié)構(gòu),每個(gè)區(qū)的大小為1M。默認(rèn)情況下, InnoDB存儲(chǔ)引擎頁大小為16K, 即一 個(gè)區(qū)中一共有64個(gè)連續(xù)的頁。
4. 頁
頁是組成區(qū)的最小單元,頁也是InnoDB 存儲(chǔ)引擎磁盤管理的最小單元,每個(gè)頁的大小默認(rèn)為 16KB。為了保證頁的連續(xù)性,InnoDB 存儲(chǔ)引擎每次從磁盤申請 4-5 個(gè)區(qū)。
5. 行
InnoDB 存儲(chǔ)引擎是面向行的(row-oriented),也就是說數(shù)據(jù)是按行進(jìn)行存放的,每個(gè)頁存放的行 記錄也是有硬性定義的,最多允許存放 16KB/2-200 行,即 7992 行記錄。
- trx_id:每次對某條聚簇索引記錄進(jìn)行改動(dòng)時(shí),都會(huì)把對應(yīng)的事務(wù)id賦值給trx_id隱藏列。
- roll_pointer:每次對某條聚簇索引記錄進(jìn)行改動(dòng)時(shí),都會(huì)把舊的版本寫入到undo日志中,然后這個(gè)隱藏列就相當(dāng)于一個(gè)指針,可以通過它來找到該記錄修改前的信息。
2.3 checkpoint
1. 介紹
由于日常的DML語句操作時(shí),首先操作的是緩沖池,并沒有直接寫入到磁盤,這有可能會(huì)導(dǎo)致內(nèi)存中的 數(shù)據(jù)與磁盤中的數(shù)據(jù)產(chǎn)生不一致的情況,而與磁盤中數(shù)據(jù)不一致的頁我們成為"臟頁"。而 checkpoint的工作,就是將內(nèi)存中的臟頁,在一定條件下刷新到磁盤。
如果在從緩沖池將頁數(shù)據(jù)刷新到磁盤的過程中發(fā)生宕機(jī),那么數(shù)據(jù)就無法恢復(fù)了;為了避免這種情況的 發(fā)生,采用了Write Ahead Log(WAL)策略,即當(dāng)事務(wù)提交時(shí),先寫重做日志(redo log),再修改 緩沖池?cái)?shù)據(jù)頁,最后通過Checkpoint刷新到磁盤(事務(wù)提交會(huì)觸發(fā)checkpoint)。這樣正在執(zhí)行的 事務(wù),因?yàn)榇嬖谌罩径伎梢员换謴?fù),沒有日志的事務(wù)還沒有執(zhí)行也不會(huì)丟失數(shù)據(jù)。
2. 作用
A. 縮短數(shù)據(jù)恢復(fù)時(shí)間
當(dāng)數(shù)據(jù)庫發(fā)生宕機(jī)時(shí),數(shù)據(jù)庫不用重做所有的日志,因?yàn)镃heckpoint之前的頁都已經(jīng)刷新會(huì)磁盤了, 故數(shù)據(jù)庫只需要重做Checkpoint之后的日志就好,這樣就大大縮短了恢復(fù)時(shí)間。
B. 緩沖池不夠用時(shí),需要先將臟頁數(shù)據(jù)刷新到磁盤中;
當(dāng)緩沖池不夠用時(shí), 根據(jù)LRU算法溢出最近最少使用的頁, 如果此頁是臟頁,則強(qiáng)制執(zhí)行 Checkpoint, 刷新臟頁到磁盤。
C. 重做日志不可用時(shí),刷新臟頁到磁盤;
redo log大小是固定的, 當(dāng)前的InnoDB引擎中, 重做日志的設(shè)計(jì)都是循環(huán)使用的,并不是無限增 大的。重做日志可以被重用的部分是已經(jīng)不再需要的, 數(shù)據(jù)庫發(fā)生宕機(jī)也不需要這部分的重做日志, 因此可以被覆蓋使用, 如果此時(shí)重做日志還需要使用,那么必須強(qiáng)制執(zhí)行Checkpoint,將緩沖池中 的頁至少刷新磁盤, checkpoint移動(dòng)到當(dāng)前重做日志的位置。

write pos表示日志當(dāng)前記錄的位置,當(dāng)ib_logfile_1寫滿后,會(huì)從ib_logfile_0從頭開始記 錄;check point表示將日志記錄的修改寫進(jìn)磁盤,完成數(shù)據(jù)落盤,數(shù)據(jù)落盤后checkpoint會(huì)將日 志上的相關(guān)記錄擦除掉,即write position ->checkpoint 之間的部分是redo log空著的部 分,用于記錄新的記錄,checkpoint->write position 之間是redo log待落盤的數(shù)據(jù)修改記 錄。當(dāng)write postion追上checkpoint時(shí),得先停下記錄,先推動(dòng)checkpoint向前移動(dòng),空出位 置記錄新的日志。
3. 分類
A. Sharp Checkpoint
Sharp Checkpoint 發(fā)生在數(shù)據(jù)庫關(guān)閉時(shí),將所有的臟頁都刷新回磁盤,這是默認(rèn)的工作方式,參 數(shù):innodb_fast_shutdown=1。
B. Fuzzy Checkpoint
在InnoDB存儲(chǔ)引擎運(yùn)行時(shí),使用Fuzzy Checkpoint進(jìn)行頁刷新,只刷新一部分臟頁。
2.4 InnoDB關(guān)鍵特性
1. 插入緩存
主鍵是行唯一的標(biāo)識符,在應(yīng)用程序中行記錄的插入順序一般是按照主鍵遞增的順序進(jìn)行插入的。因 此,插入聚集索引一般是順序的,不需要磁盤的隨機(jī)讀取。因此,在這樣的情況下,插入操作一般很快 就能完成。
但是,不可能每張表上只有一個(gè)聚集索引,在更多的情況下,一張表上有多個(gè)非聚集的輔助索引 (secondary index)。比如,我們還需要按照name這個(gè)字段進(jìn)行查找,并且name這個(gè)字段不是唯 一的, 這樣的情況下產(chǎn)生了一個(gè)非聚集的并且不是唯一的索引。在進(jìn)行插入操作時(shí),數(shù)據(jù)頁的存放還是 按主鍵id的執(zhí)行順序存放,但是對于非聚集索引,葉子節(jié)點(diǎn)的插入不再是順序的了。這時(shí)就需要離散地 訪問非聚集索引頁,插入性能在這里變低了。然而這并不是這個(gè)name字段上索引的錯(cuò)誤,因?yàn)锽+樹的 特性決定了非聚集索引插入的離散性。
InnoDB存儲(chǔ)引擎開創(chuàng)性地設(shè)計(jì)了插入緩沖,對于非聚集索引的插入或更新操作,不是每一次直接插入 索引頁中,而是先判斷插入的非聚集索引頁是否在緩沖池中。如果在,則直接插入;如果不在,則先放 入一個(gè)插入緩沖區(qū)中,好似欺騙數(shù)據(jù)庫這個(gè)非聚集的索引已經(jīng)插到葉子節(jié)點(diǎn)了,然后再以一定的頻率執(zhí) 行插入緩沖和非聚集索引葉子節(jié)點(diǎn)的合并操作,這時(shí)通常能將多個(gè)插入合并到一個(gè)操作中(因?yàn)樵谝粋€(gè) 索引頁中),這就大大提高了對非聚集索引執(zhí)行插入和修改操作的性能。

2. 兩次寫
當(dāng)數(shù)據(jù)庫寫物理頁時(shí),如果宕機(jī)了,那么可能會(huì)導(dǎo)致物理頁的一致性被破壞。
可能有人會(huì)說,重做日志不是可以恢復(fù)物理頁嗎?實(shí)際上是的,但是要求是在物理頁一致的情況下。也就是說,如果物理頁完全是未寫之前的狀態(tài),則可以用重做日志恢復(fù)。如果物理頁已經(jīng)完全寫完了, 那么也可以用重做日志恢復(fù)。但是如果物理頁前面2K寫了新的數(shù)據(jù),但是后面2K還是舊的數(shù)據(jù),則種 情況下就無法使用重做日志恢復(fù)了。
這里的兩次寫就是保證了物理頁的一致性,使得即使宕機(jī),也可以用重做日志恢復(fù)。在寫物理頁時(shí),并不是直接寫到真正的物理頁上去,而是先寫到一個(gè)臨時(shí)頁上去,臨時(shí)頁寫完后,再寫 物理頁。這樣一來:
- A. 如果寫臨時(shí)頁時(shí)宕機(jī)了,物理頁還是完全未寫之前的狀態(tài),可以用重做日志恢復(fù)
- B. 如果寫物理頁時(shí)宕機(jī)了,則可以使用臨時(shí)頁來恢復(fù)物理頁
每次寫物理頁時(shí),先寫到double write buffer中,然后從double write buffer寫到double write上去。最后再從double write buffer寫到物理頁上去。

3. 自適應(yīng)hash索引
在InnoDB中默認(rèn)支持的索引結(jié)構(gòu)為 B+ 樹,B+ 樹索引可以使用到范圍查找,同時(shí)是按照順序的方式 對數(shù)據(jù)進(jìn)行存儲(chǔ),因此很容易對數(shù)據(jù)進(jìn)行排序操作,在聯(lián)合索引中也可以利用部分索引鍵進(jìn)行查詢 。而對于Hash索引則只能滿足 =,<>,in查詢,不能使用范圍查詢, 而且數(shù)據(jù)的存儲(chǔ)是沒有順序的。
MySQL 默認(rèn)使用 B+ 樹作為索引,因?yàn)?B+ 樹有著 Hash 索引沒有的優(yōu)點(diǎn),那么為什么還需要自 適應(yīng) Hash 索引呢?
這是因?yàn)锽+樹的查找次數(shù),取決于B+樹的高度,在生產(chǎn)環(huán)境中,B+樹的高度一般為3-4層,故需要3-4 次查詢。而 Hash 索引在進(jìn)行數(shù)據(jù)檢索的時(shí)候效率非常高,通常只需要 O(1) 的復(fù)雜度,也就是一 次就可以完成數(shù)據(jù)的檢索。雖然 Hash 索引的使用場景有很多限制,但是優(yōu)點(diǎn)也很明顯。InnoDB存儲(chǔ) 引擎會(huì)監(jiān)控對表上各索引頁的查詢,如果觀察到hash索引可以提升速度,則建立hash索引,稱之為自 適應(yīng)hash索引(Adaptive Hash Index,AHI)。
注意,這里的自適應(yīng)指的是不需要人工來指定,系統(tǒng)會(huì)根據(jù)情況自動(dòng)完成。
什么情況下才會(huì)使用自適應(yīng) Hash 索引呢?如果某個(gè)數(shù)據(jù)經(jīng)常被訪問,當(dāng)滿足一定條件的時(shí)候,就會(huì) 將這個(gè)數(shù)據(jù)頁的地址存放到 Hash 表中。這樣下次查詢的時(shí)候,就可以直接找到這個(gè)頁面的所在位 置。值得注意的是,hash索引只能用于= ,in的查詢,對于其他的查詢類型,如范圍匹配等是不能使 用hash索引的。而且自適應(yīng) Hash 索引只保存熱數(shù)據(jù)(經(jīng)常被使用到的數(shù)據(jù)),并非全表數(shù)據(jù)。因此 數(shù)據(jù)量并不會(huì)很大,因此自適應(yīng) Hash 也是存放到緩沖池中,這樣也進(jìn)一步提升了查找效率。

4. 異步IO
為了提高磁盤的操作性能,在InnoDB存儲(chǔ)引擎中使用異步非阻塞AIO的方式來操作磁盤。
與AIO對應(yīng)的是Sync IO,如果是同步IO操作,則每進(jìn)行一次IO操作,需要等待此次操作結(jié)束后才可 以進(jìn)行接下來的操作。但是如果用戶發(fā)出的是一條索引掃描的查詢,那么這條SQL查詢語句可能需要掃 描多個(gè)索引頁,也就是需要進(jìn)行多次的IO操作。每掃描一個(gè)頁并等待其完成之后,再進(jìn)行下一次掃描, 這是沒有必要的。
用戶可以在發(fā)出一個(gè)IO請求后立即再發(fā)出另一個(gè)IO請求,當(dāng)全部的IO請求發(fā)送完畢后,等待所有的IO 操作完成,這就是AIO。
5. 刷新臨接頁
InnoDB提供刷新臨近頁功能:當(dāng)刷新一臟頁時(shí),同時(shí)檢測所在區(qū)(extent)的所有頁,如果有臟頁則 一并刷新,好處則是通過AIO特性合并寫IO請求,缺點(diǎn)則是有些頁不怎么臟也好被刷新,而且頻繁的更 改那些不怎么臟的頁又很快變成臟頁,造成頻繁刷新。對于固態(tài)磁盤則考慮關(guān)閉此功能(將 innodb_flush_neighbors設(shè)置為0)。
2.5 InnoDB事務(wù)
事務(wù)可由一條簡單的SQL語句組成,也可以由一組復(fù)雜的SQL語句組成。事務(wù)是訪問并更新數(shù)據(jù)庫中各 個(gè)數(shù)據(jù)項(xiàng)的一個(gè)程序執(zhí)行單元。在事務(wù)操作時(shí),這組執(zhí)行單元中的SQL,要么全部成功, 要么全部失 敗。
1. 事務(wù)具有以下四個(gè)特性(ACID)

2. 隔離級別
并發(fā)事務(wù)帶來的問題:

為了解決上述提到的事務(wù)并發(fā)問題,數(shù)據(jù)庫提供一定的事務(wù)隔離機(jī)制來解決這個(gè)問題。數(shù)據(jù)庫的事務(wù)隔 離越嚴(yán)格,并發(fā)副作用越小,但付出的代價(jià)也就越大,因?yàn)槭聞?wù)隔離實(shí)質(zhì)上就是使用事務(wù)在一定程度上 “串行化” 進(jìn)行,這顯然與“并發(fā)” 是矛盾的。
數(shù)據(jù)庫的隔離級別有4個(gè),由低到高依次為Read uncommitted、Read committed、Repeatable read、Serializable,這四個(gè)級別可以逐個(gè)解決臟寫、臟讀、不可重復(fù)讀、幻讀這幾類問題。

3. 實(shí)現(xiàn)
1). redo log
redo log叫做重做日志,是用來實(shí)現(xiàn)事務(wù)的持久性。該日志文件由兩部分組成:重做日志緩沖(redo log buffer)以及重做日志文件(redo log),前者是在內(nèi)存中,后者在磁盤中。當(dāng)事務(wù)提交之后 會(huì)把所有修改信息都會(huì)存到該日志中, 用于在刷新臟頁到磁盤時(shí),發(fā)生錯(cuò)誤時(shí), 進(jìn)行數(shù)據(jù)恢復(fù)使用。例:

執(zhí)行事務(wù)操作
- start transaction;
- select balance from bank where name="Tom";
- -- 生成 重做日志 balance=8000
- update bank set balance = balance - 2000;
- -- 生成 重做日志 account=2000
- update finance set account = account + 2000;
- commit;
流程

mysql 為了提升性能不會(huì)把每次的修改都實(shí)時(shí)同步到磁盤,而是會(huì)先存到Buffer Pool(緩沖池)里 頭,把這個(gè)當(dāng)作緩存來用。然后使用后臺(tái)線程將緩存池刷新到磁盤。
當(dāng)在執(zhí)行刷新時(shí),宕機(jī)或者斷電,可能會(huì)丟失部分?jǐn)?shù)據(jù)。所以引入了redo log來記錄已成功提交事務(wù) 的修改信息,并且在事務(wù)提交時(shí)會(huì)把redo log持久化到磁盤,系統(tǒng)重啟之后在讀取redo log恢復(fù)最 新數(shù)據(jù)。
簡單來說 , redo log是用來恢復(fù)數(shù)據(jù)的 用于保障,已提交事務(wù)的持久化特性 ;
2). undo log
undo log 叫做回滾日志,用于記錄數(shù)據(jù)被修改前的信息。他正好跟前面所說的重做日志所記錄的相 反,重做日志記錄數(shù)據(jù)被修改后的信息。undo log主要記錄的是數(shù)據(jù)的邏輯變化,為了在發(fā)生錯(cuò)誤時(shí) 回滾之前的操作,需要將之前的操作都記錄下來,然后在發(fā)生錯(cuò)誤時(shí)才可以回滾。

undo log 記錄事務(wù)修改之前版本的數(shù)據(jù)信息,因此假如由于系統(tǒng)錯(cuò)誤或者rollback操作而回滾的話 可以根據(jù)undo log的信息來進(jìn)行回滾到?jīng)]被修改前的狀態(tài)。
三 存儲(chǔ)引擎應(yīng)用場景
在選擇存儲(chǔ)引擎時(shí),應(yīng)該根據(jù)應(yīng)用系統(tǒng)的特點(diǎn)選擇合適的存儲(chǔ)引擎。對于復(fù)雜的應(yīng)用系統(tǒng),還可以根據(jù) 實(shí)際情況選擇多種存儲(chǔ)引擎進(jìn)行組合。以下是幾種常用的存儲(chǔ)引擎的使用環(huán)境 。
- InnoDB : 是Mysql的默認(rèn)存儲(chǔ)引擎,用于事務(wù)處理應(yīng)用程序,支持外鍵, 行鎖。如果應(yīng)用對事務(wù)的完整性有比較高的要求,在并發(fā)條件下要求數(shù)據(jù)的一致性,數(shù)據(jù)操作除了插入和查詢以外,還包含很多的更新、刪除操作,那么InnoDB存儲(chǔ)引擎是比較合適的選擇。InnoDB存儲(chǔ)引擎除了有效的降低由于刪除和更新導(dǎo)致的鎖定, 還可以確保事務(wù)的完整提交和回滾,對于電商系統(tǒng)中的商品(SPU、SKU、分類、品牌)、訂單、用戶等信息的存儲(chǔ),InnoDB是最合適的選擇。
- MyISAM : 如果應(yīng)用是以讀操作和插入操作為主,只有很少的更新和刪除操作,并且對事務(wù)的完整性、并發(fā)性要求不是很高,那么選擇這個(gè)存儲(chǔ)引擎是非常合適的。對于電商系統(tǒng)中,系統(tǒng)的操作日志、用戶評價(jià)、足跡等信息的存儲(chǔ),MyISAM是合適的選擇。