天天看點

從一條更新SQL的執行過程窺探InnoDB之REDOLOG

1 前言

資料庫為了取得更好的讀寫性能,InnoDB會将資料緩存在記憶體中(InnoDB Buffer Pool),對磁盤資料的修改也會落後于記憶體,這時如果程序或機器崩潰,會導緻記憶體資料丢失,為了保證資料庫本身的一緻性和持久性,InnoDB維護了REDO LOG。修改Page之前需要先将修改的内容記錄到REDO中,并保證REDO LOG早于對應的Page落盤,也就是常說的WAL,Write Ahead Log。當故障發生導緻記憶體資料丢失後,InnoDB會在重新開機時,通過重放REDO,将Page恢複到崩潰前的狀态。

2 MYSQL更新語句的執行過程

2.1 MYSQL的體系結構

大體來說,MySQL 可以分為 用戶端、Server層和存儲引擎層三大部分,如圖所示。

Server 層包括連接配接器、查詢緩存、分析器、優化器、執行器等,涵蓋 MySQL 的大多數核心服務功能,以及所有的内置函數(如日期、時間、數學和加密函數等),所有跨存儲引擎的功能都在這一層實作,比如存儲過程、觸發器、視圖等。

存儲引擎層負責資料的存儲和提取。其架構模式是插件式的,支援 InnoDB、MyISAM、Memory 等多個存儲引擎。現在最常用的存儲引擎是 InnoDB,它從 MySQL 5.5.5 版本開始成為了預設存儲引擎。

從一條更新SQL的執行過程窺探InnoDB之REDOLOG

2.2 更新SQL的執行

當我們執行一條更新SQL時是如何執行的呢,下面執行一條簡單的SQL更新語句(預設存儲引擎InnoDB)

update T set c=c+1 where ID=2;      

第一步:連接配接器

先通過連接配接器連接配接到這個資料庫上。連接配接器負責跟用戶端建立連接配接、校驗使用者名密碼的正确性,同時擷取該使用者的權限放到緩存中、維持和管理連接配接

第二步:緩存

連接配接建立完成後,如果執行的是SELECT查詢 語句會查詢緩存中是否存在該SQL的結果集,如果存在結果則再校驗使用者表和資料的權限最終将查詢到的結果傳回。如果是UPDATE,DELETE等更新操作,那麼跟這個表有關的查詢緩存會置為失效,是以這條語句就會把表 T 上所有緩存結果都清空。

第三步:分析器

如果沒有命中查詢緩存,就要開始真正執行語句了。首先,MySQL 需要知道你要做什麼,是以需要對 SQL 語句做解析。

分析器先會做“詞法分析”。你輸入的是由多個字元串和空格組成的一條 SQL 語句,MySQL 需要識别出裡面的字元串分别是什麼,代表什麼。例如該語句中c列在表T中是否存在等。

做完了這些識别以後,就要做“文法分析”。根據詞法分析的結果,文法分析器會根據文法規則,判斷你輸入的這個 SQL 語句是否滿足 MySQL 文法。該SQL語句中的update、where 等是否符合SQL文法

第四步:優化器

經過了分析器,MySQL 就知道你要做什麼了。在開始執行之前,還要先經過優化器的處理。優化器是在表裡面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯(join)的時候,決定各個表的連接配接順序;優化器決定要使用 ID 這個索引。指定索引也就指定了後面的執行器需要調用存儲引擎的哪個接口進行執行。

第五步:執行器

MySQL 通過分析器知道了你要做什麼,通過優化器知道了該怎麼做,于是就進入了執行器階段,開始執行語句。開始執行的時候,要先判斷一下你對這個表 T 有沒有執行查詢的權限,如果沒有,就會傳回沒有權限的錯誤。執行器負責具體執行,找到這一行,然後更新。

從一條更新SQL的執行過程窺探InnoDB之REDOLOG

2.3 InnoDB存儲引擎引入REDOLOG

Mysql本身有自己的日志記錄binlog(歸檔日志:分為row,statement,mix三種模式),但是隻依靠binlog是沒有crash-safe能力的,是以在存儲引擎層InnoDB使用另外一套日志系統redolog來實作crash-safe能力。同時為了取得更好的讀寫性能,InnoDB會将資料緩存在記憶體中(InnoDB Buffer Pool),對磁盤資料的修改也會落後于記憶體,這時如果程序或機器崩潰,會導緻記憶體資料丢失,進而保證資料庫本身的一緻性和持久性。修改Page之前需要先将修改的内容記錄到REDO中,并保證REDO LOG早于對應的Page落盤,也就是常說的WAL,Write Ahead Log。當故障發生導緻記憶體資料丢失後,InnoDB會在重新開機時,通過重放REDO,将Page恢複到崩潰前的狀态。

那麼我們需要什麼樣的REDO呢?

首先,REDO的維護增加了一份寫盤資料,同時為了保證資料正确,事務隻有在他的REDO全部落盤才能傳回使用者成功,REDO的寫盤時間會直接影響系統吞吐,顯而易見,REDO的資料量要盡量少。其次,系統崩潰總是發生在始料未及的時候,當重新開機重放REDO時,系統并不知道哪些REDO對應的Page已經落盤,是以REDO的重放必須可重入,即REDO操作要保證幂等。最後,為了便于通過并發重放的方式加快重新開機恢複速度,REDO應該是基于Page的,即一個REDO隻涉及一個Page的修改。

資料量小是Logical Logging的優點,而幂等以及基于Page正是Physical Logging的優點。InnoDB采取了一種稱為Physiological Logging的方式,來兼得二者的優勢。所謂Physiological Logging,就是以Page為機關,但在Page内以邏輯的方式記錄。舉個例子,一種作用于Page類型的REDOLOG中記錄了對Page中一個Record的修改,方法如下:

(Page ID,Record Offset,(Filed 1, Value 1) … (Filed i, Value i) … )      

其中,PageID指定要操作的Page頁,Record Offset記錄了Record在Page内的偏移位置,後面的Field數組,記錄了需要修改的Field以及修改後的Value。

2.4 REDOLOG的記錄内容

從一條更新SQL的執行過程窺探InnoDB之REDOLOG

其中Type就是記錄的作用對象(根據REDO記錄不同的作用對象,可劃分為三個大類:作用于Page,作用于Space以及提供額外資訊的Logic類型),Space ID和Page Number唯一辨別一個Page頁,這三項是所有REDO記錄都需要有的頭資訊。

3 總結

作者:王義傑