1. 程式人生 > >Mysql 中寫操作時保駕護航的三兄弟!

Mysql 中寫操作時保駕護航的三兄弟!

這期的文章主要是講述寫操作過程中涉及到的三個日誌檔案,看過前幾期的話可能你或多或少已經有些瞭解了(或者從別的地方也瞭解過)。比如整個寫操作過程中用到的兩階段提交,又或者是操作過程中涉及到的日誌檔案,但是總體來說不是很系統更談不上全面。

今天我們就來會會這三兄弟。

圖注:思維導圖

兩階段提交

這個名詞你應該聽到過很多次了,在這裡再介紹下這位老朋友。

所謂的兩階段提交,從字面意思來看應該是有兩個步驟來進行約束的。事實上也是如此。這兩個步驟中的主角就是我們今天要講的重要角色中的兩位:binlog 和 redo log。

提到兩階段提交,SQL 語句的執行流程就繞不過去了。沒轍,雖然提了很多遍,但還得再拉出來溜溜。只不過這次的側重點和前面的會有些不同。

具體到操作流程上是這樣的:

當執行某個寫操作的 SQL 時,引擎將這行資料更新到記憶體的同時把對應的操作記錄到 redo log 裡面,然後處於 prepare 狀態。並把完成資訊告知給執行器。

執行器生成對應操作的 binlog,並把 binlog 寫入磁盤裡。然後呼叫引擎的提交事務介面,變更 redo log 狀態為 commit,這樣操作就算完成了。

好了,知道了兩階段提交後,我們接下來看看這些日誌檔案的真面目。 

重做日誌(redo log)

首先出場的是位於儲存引擎層的 redo log,它是用來記錄在"資料頁做了什麼修改"的物理日誌檔案。

WAL 技術

提到 redo log,WAL 技術必然是繞不過去的,全稱是 Write-Ahead Logging。也就是在同步磁碟前先寫日誌,然後系統再根據一定的策略將日誌裡的記錄同步到磁盤裡。

存在的必要性

從上邊的兩階段提交的過程裡,我們可以看到 WAL 技術的使用場景。不知道你有沒有疑惑,為什麼中間非要寫 redo log,直接將更新結果同步到磁盤裡不行嗎?傻孩子,同步到磁盤裡就意味著每次寫操作就得產生隨機寫盤操作,速度得多慢啊。

機智的你可能會說了,那我能不能一定的時間後從記憶體再同步到磁盤裡,這種方式不行嗎?來,先給你個腦瓜崩,你想想,我服務重啟了,這些資料還在不?記憶體是易失的,不知道什麼異常情況就會導致資料丟失。所以這時候就需要一個能持久化的中間檔案,起到"緩衝"的作用,並且寫入速度還不慢。

那麼 redo log 就應運而生了。雖然同樣儲存在磁碟上,但是順序寫入在速度上並不受影響(疑惑的同學可以瞭解下磁碟的隨機與順序讀寫的區別)。

當然 redo log 除了能起到"延遲"同步磁碟檔案的作用外,在資料庫伺服器宕機時,還可以用來恢復資料。

寫入時機 

談到寫入時機,是不是更疑惑了,難倒不是更新完記憶體就寫入 redo log 檔案嗎?答案確實不是,因為中間還有一個 redo log buffer(記憶體中) 。Mysql 每執行一條語句,會先將記錄寫入 redo log buffer,後續執行 commit 操作時會以一定的時機寫入到 redo log 檔案(磁碟上)中。

值得注意的是,redo log buffer 裡的資料是在執行 commit 操作時寫入到 redo log 檔案中的。

至於寫入的時機,則由下面的引數來控制的: 

 

 

(圖片源自網路)

寫入方式 

知道了寫入時機,這裡簡單介紹下寫入的方式吧。在 Innodb 中,redo log 的大小是固定的,那麼就只能是以迴圈的方式進行寫入了。假如當前我有 4 個檔案,從第一個檔案開始寫入,直到最後一個檔案寫滿為止,再回到開頭將資料同步至檔案後擦除掉繼續寫。

圖中的 write pos 表示當前記錄的位置,隨著不斷寫入逐漸後移。當寫到 ib_logfile_3號檔案時,整個 redo log 就被寫滿了。此時更新操作就會被阻塞。系統根據 check point 標記位來擦除掉一些記錄(當然前提是把這些記錄同步至磁碟)。

總得來看 redo log 的寫入方式就是一個不斷寫入,寫滿後擦除,又寫入的過程。

二進位制日誌(binlog) 

說完了 redo log,我們再來看看另一個位於服務層的二進位制日誌檔案 binlog,這位大兄弟扮演的角色是儲存邏輯日誌的,所謂的邏輯日誌就是指修改了什麼,都會記錄其中。

例如:對 id = 1 的欄位進行更新操作。

當然除了記錄操作過程外,它還有支援主從同步及資料異常恢復的能力。

寫入模式 

binlog 中有三種寫入模式,我們分別來看下有什麼不同及對應的優缺點:

(圖片源自網路)

寫入方式

與 redo log 迴圈寫不同的是, binlog 採用追加的方式寫入,當一個檔案寫到一定大小後就會切換到另一個。

與 redo log 的關聯

在上面的兩階段提交裡我們有提到過在寫入binlog 後會呼叫引擎的提交事務介面,變更 redo log 狀態為 commit。那麼它是如何找到對應的記錄,或者換句話說,它們兩者是怎麼關聯起來的呢?

答案是通過一個共同的欄位 XID,不僅在事務提交時,在崩潰恢復的時候如果遇到僅寫入 prepare 而沒有 commit 的 redo log,也可以通過 XID 去尋找對應的事務。

回顧下寫流程

到這裡我們有必要回顧下寫流程的操作,以更新某個欄位為例:

回滾日誌(undo log) 

到這裡,你可能會疑惑了,通篇裡哪有 undo log 的影子,你個渣男!

別急,來了!

根據字面意思,你應該能猜出來它是幹啥的。回滾嘛,也就是給你一次後悔的機會。在進行資料修改時,同時記錄 undo log,即同時記錄相反操作的邏輯日誌。你可以理解為操作 update 的時候,寫一條對應相反的 update 記錄,操作 delete 的時候,寫一條對應的 insert 記錄。 

當事務回滾時。從 undo log 中讀取到對應的邏輯記錄就可以進行回滾操作了。

總結

兩階段提交

  • 兩階段提交過程中,更新記憶體的同時把對應操作記錄到 redo log 中,並把生成的binlog 寫入磁碟後提交事務。

重做日誌 

  • redo log 是位於儲存引擎層的物理日誌,用來記錄在“資料頁做了什麼修改”的物理日誌檔案。採用迴圈寫的方式,記錄資料被修改後的樣子。同時還提供資料恢復的能力。

二進位制日誌

  • binlog是位於服務層的邏輯日誌,用來記錄“對資料做了什麼修改”的日誌檔案。與 redo log 不同的是,可以一直進行追加寫入。同時還提供主從同步及資料異常恢復的能力。

回滾日誌 

  • 在資料修改時,同時記錄 undo log,可以確保在事務回滾操作時進行資料還原。

關於作者

作者:大家好,我是萊烏,BAT搬磚工一枚。從小公司進入大廠,一路走來收穫良多,想將這些經驗分享給有需要的人,因此建立了公眾號【IT界農民工】。定時更新,希望能幫助到你。同時,我給大家肝了一份Redis面經手冊,在我的公眾號內回覆【pdf】即可獲取,希望對你有所幫助。

相關推薦

Mysql 操作保駕護航兄弟

這期的文章主要是講述寫操作過程中涉及到的三個日誌檔案,看過前幾期的話可能你或多或少已經有些瞭解了(或者從別的地方也瞭解過)。比如整個寫操作過程中用到的兩階段提交,又或者是操作過程中涉及到的日誌檔案,但是總體來說不是很系統更談不上全面。 今天我們就來會會這三兄弟。 圖注:思維導圖 兩階段提交 這個名詞你應該

pl/sql developerSQL出現ORA-06550和PLS-00553

ORA-06550 PLS-00553 pl/sql 【現象】在pl/sql中寫SQL時,出現一些問題。ORA-06550:亂碼PLS-00553:亂碼ORA-06550:亂碼PL/SQL:Compilation unit analysis terminated【原因】由於Oracle的系統配置文

mysql新增資料,報錯(incorrect string value:'\xf0\x9f ) 字元轉換不正確

原因是UTF-8編碼有可能是兩個、三個、四個位元組。Emoji表情或者某些特殊字元是4個位元組,而Mysql的utf8編碼最多3個位元組,所以資料插不進去。 在網上搜了一下解決問題的方案,我選了一個方案解決了。 1.在mysql的安裝目錄下找到my.ini,作如下修改: [mys

關於MYSQL進行insert操作,存在則更新不存在則插入的解決辦法

在專案開發中經常會遇到資料頻發插入操作且需要進行判斷,這樣會業務層多一次判斷的操作,多請求一次資料庫,造成效能問題,所以採用以下辦法解決了這個令人藍瘦的問題。。。 這裡是一個使用者運動記錄表,記錄使用者每天的運動時間,走的路程,消耗的能量和走的步數,前臺是定時一分鐘向後臺傳送

用python向txt檔案資料的追加和覆蓋問題

  最近在用python從WOS網站中爬取內容並儲存到本地的txt檔案中,發現每次寫入都是把txt檔案中原來存在的內容覆蓋掉了,那麼如何才能在原來的基礎上繼續往裡面新增內容呢? 1、原來的開啟檔案的方式是: file = open(pathTxt, 'w', encoding

mysql授權操作

先設定該使用者只有show database許可權 grant select,insert,update,delete on redmine1.* to [email protected]”%” identified by “jira”; 新增超級

Python在mysql進行操作是十分容易和簡潔的

首先宣告一下,我用的是Windows系統! 1、在Python中對mysql資料庫進行操作首先要匯入pymysql模組,預設情況下,Python中是沒有安裝這個模組的, 可以在Windows的命令列中用pip install pymysql來安裝(注意要連網

vs2012及以上版本c++自動給程式碼新增建立資訊註釋的問題

寫多了,就煩了,如果系統能自動生成就好了。 確實在寫java等語言時,能輕鬆做到這些,甚至包括生成實時的日期時間,當前的檔名等其他同步資訊。 然而在vs上,對C#能完成這些設定,但是對c++卻沒那麼給力了。 你可能在網上見到很多如下說法: 在VS安裝

MySQL 處理 Null 要注意兩個陷阱

MySQL資料庫是一個基於結構化資料的開源資料庫。SQL語句是MySQL資料庫中核心語言。不過在MySQL資料庫中執行SQL語句,需要小心兩個陷阱。 陷阱一:空值不一定為空 空值是一個比較特殊的欄位。在MySQL資料庫中,在不同的情形下,空值往往代表不同的含義。這是M

MySQL 進行 Replace 操作造成資料丟失——那些坑你踩了嗎?

 原文章地址:http://mp.weixin.qq.com/s/nCryxMQK00ZjjuTsfYvk3w 一、問題說明 公司開發人員在更新資料時使用了 replace into 語句,由於使用不當導致了資料的大量丟失,到底是如何導致的資料丟失?現分析

mysql dbhelper

using System; using System.Collections.Generic; using System.Text; using System.Data; using MySql.Data.MySqlClient; namespace i_salesDAL

潤乾報表在linux環境換行字型顯示不全

問題現象: 潤乾報表在linux環境中單元格設定為自動換行,字型也設定為linux環境中存在的宋體,但換行時依舊顯示不全!如下圖所示: 自動換行後的只顯示一半 解決方法: 1.網上有方法

Ubuntu18.04安裝caffe(cpu)—-簡單易操作:只需

99.9%的股民都想入的群!穩抓牛股

MySQL的這個池子,強的一批

Mysql 中資料是要落盤的,這點大家都知道。讀寫磁碟速度是很慢的,尤其和記憶體比起來更是沒的說。但是,我們平時在執行 SQL 時,無論寫操作還是讀操作都能很快得到結果,並沒有預想中的那麼慢。 可能你會說我有索引啊,有索引當然快了。但是鐵子,索引檔案也是儲存在磁碟上的,查詢過程會產生磁碟 I/O。如果同時對

MySQL基礎知識()——資料表記錄讀操作

首先建立一個users表,後續我們都對這個表的資料進行操作。 // 建立users表。 // 包含欄位編號id;使用者名稱username;密碼password;年齡age;薪水salary;性別sex,預設值為‘3’ CREATE TABLE IF NOT EXISTS users(id IN

Json 讀操作含有中文

Python讀寫 json 檔案的簡單實現 當要讀寫的內容有“中文”字元時, json.dump(data, f, ensure_ascii=False) 將 ensure_ascii 設為 Fal

MySQL使用INNER JOIN來實現Intersect並集操作

int isam har 業務 charset tin ner get 一句話 MySQL中使用INNER JOIN來實現Intersect並集操作 一、業務背景 我們有張表設計例如以下: CREATE TABLE `user_defined_value` (

QSerialPort的線程常用操作(包含心跳,讀方法等)

exp tab else rect 信號 ttl tag fine blog 1 #ifndef DATACOMMSERIAL_H 2 #define DATACOMMSERIAL_H 3 4 #include <QThread> 5 #inclu

MySQL left join操作 on與where放置條件的區別

合成 可見 找到 需要 兩張 oca aaa rip 多個 優先級 兩者放置相同條件,之所以可能會導致結果集不同,就是因為優先級。on的優先級是高於where的。 1 1 首先明確兩個概念: LEFT JOIN 關鍵字會從左表 (table_name1) 那裏返回

[Word]解決Word執行輸入操作後面字符自動被刪除的問題

字符 位置 狀態 問題 找不到 輸入 自動 就會 題解 問題分析:這是由於當前輸入方式為“改寫”,在此方式下,如果某個位置處後面有其他字符,當在此位置執行輸入操作時,就會默認刪除其後的所有字符。 解決方案:Word窗口下邊緣狀態欄,找到“改寫”按鈕,點擊,使其切換為“插入”