MySQL 查詢執行的程序鏈接
Select陳述句的執行程序會經過連接器、分析器、優化器、執行器、存盤引擎,同樣的 Update陳述句也會同樣走一遍 Select陳述句的執行程序,
但是和 Select最大不同的是,Update陳述句會涉及到兩個日志的操作 redo log(重做日志) 和 binlog (歸檔日志),
那么 Mysql中又是怎么使用 redo log和 binlog?為什么要使用 redo log和 binlog呢?直接執行更新然后存庫不就行了嗎?還要放在 redo log和 binlog中,這不是多此一舉嗎?且聽我慢慢道來,這里面大有文章,
redo log
大家都是知道 Mysql是關系型資料庫,用來存盤資料的,在訪問資料庫量大的時候,Mysql讀寫磁盤訪問的效率是非常低的,加上 sql中的條件對資料的篩選過濾,那么效率就更低了,這也是為什么引入非關系型資料庫作為作為資料快取原因,例如:Redis、MongoDB等,就是為了減少 sql執行期間的資料庫 io操作,
同樣的道理,若是每次執行 update陳述句都要進行磁盤 io操作、以及資料的過濾篩選,小量的訪問和資料量資料庫還可以撐住,那么訪問量一大以及資料量一大,這樣資料庫肯定頂不住,基于上面的問題于是出現了redo log日志,redo log日志也叫做 WAL技術(Write-Ahead Logging),他是一種先寫日志,并更新記憶體,最后再更新磁盤的技術,并且更新磁盤往往是在 Mysql比較閑的時候,這樣就大大減輕了 Mysql的壓力,
redo log的特點就是:redo log是固定大小,是物理日志,屬于 InnoDB引擎的,并且寫 redo log是環狀寫日志的形式:
如上圖所示:若是四組的redo log檔案,一組為1G的大小,那么四組就是4G的大小,其中 write pos是記錄當前的位置,有資料寫入當前位置,那么write pos就會邊寫入邊往后移,而 check point是擦除的位置,因為redo log是固定大小,所以當redo log滿的時候,也就是 write pos追上 check point的時候,需要清除 redo log的部分資料,清除的資料會被持久化到磁盤中,然后將 check point向前移動,redo log日志實作了即使在資料庫出現例外宕機的時候,重啟后之前的記錄也不會丟失,這就是 crash-safe能力,
binlog
binlog稱為歸檔日志,是邏輯上的日志,它屬于 Mysql Server層面的日志,記錄著 sql的原始邏輯,主要有兩種模式,一個是 statement格式記錄的是原始的sql,而 row格式則是記錄行內容,那么這樣看來 redo log和 binlog雖然記錄的形式、內容不同,但是這兩者日志都能通過自己記錄的內容恢復資料,那么為什么還要這兩個日志同時存在呢?只要其中一個不就行了嘛,兩個同時存在不就多此一舉了嘛,且聽我慢慢道來,這里面也大有文章,
因為剛開 Mysql自帶的引擎 MyISAM就沒有 crash-safe功能的,并且在此之前 Mysql還沒有 InnoDB引擎,Mysql自帶的 binlog日志只是用來歸檔日志的,所以 InnoDB引擎也就通過自己 redo log日志來實作 crash-safe功能,
update執行程序
上面說了那么久兩種日志的作用和特點,那么這兩種日志究竟和 update執行陳述句有什么關系呢?先來看圖:
前提:當前的引擎是使用InnoDB,update陳述句與 select陳述句區別主要是這兩日志的使用主要是在執行器和引擎之間進行互動時體現的區別,假如執行如下一條簡單的更新陳述句是:
update user set age=age+1 where id =2;
上面說過 select陳述句走過的流程 update陳述句也會走一遍,當來到執行器的時候:
【1】執行器會呼叫引擎的讀介面,然后找到 id=2的資料行,因為 id是主鍵索引,索引按照樹的搜索找到這一行, 若是資料行已經存在于記憶體的資料頁中就會立即將結果回傳,若是不在記憶體中,就會從磁盤中進行加載到記憶體中,然后將查詢的結果回傳,
【2】執行器將回傳的結果的age欄位+1,并呼叫引擎的寫介面寫入更新后的資料行,
【3】引擎獲取到更新后的資料行更新到記憶體和 redo log(也是寫入磁盤,順序寫入,比較快)中,并告訴執行器可以隨時提交事務,此時的 redo log處于 prepare階段,
【4】執行器收到引擎的告知后,生成 binlog日志,并且呼叫引擎的介面提交事務,引擎將 redo log的狀態修改為 commit狀態,這樣這個更新操作算是完成,
兩階段提交
上面詳細的說了update陳述句的執行流程,提到了redo log的 prepare 和 commit兩個階段,這就是兩階段提交,兩階段提交的目的是為了保證 redo log日志與 binlog日志保持資料的一致性,若是 redo log寫成功 binlog寫失敗,或者 redo log寫失敗 binlog寫成功,最后使用這兩者日志進行資料恢復得到的結果資料都是不一致性的,所以為了保證兩個日志邏輯上的一致,使用兩階段進行提交,
redo log 與 binlog的總結
最后來對比一下這兩種日志:redo是物理的,binlog是邏輯的,redo的大小固定,并且以環狀的形式寫入資料,資料滿的時候需要將 redo日志中擦除資料,并且將擦除的資料持久化到磁盤中,而 binlog以追加日志的形式寫入,也就是當日志寫到一定大小后,就會切換到下一個,并不會覆寫以前寫的日志,binlog 是在 Mysql Server層中使用,因為 binlog沒有 crash-safe功能,所以 InnoDB引擎自己實作了 redo log日志的 crash-safe的功能,為了保證這兩個日志邏輯上的一致使用兩階段提交,在使用 redo和 binlog這兩種日志的時候,可以將引數 innodb_flush_log_at_trx_commit和 sync_binlog都設定為1,它表示每次事務提交的時候,都會將日志持久化到磁盤中,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/204023.html
標籤:其他
