最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL保證數(shù)據(jù)不丟失的方案詳解

 更新時間:2023年12月21日 09:59:07   作者:王二蛋!  
MySQL作為一個存儲數(shù)據(jù)的產(chǎn)品,怎么確保數(shù)據(jù)的持久性和不丟失才是最重要的,感興趣的可以跟隨本文一探究竟,文中通過圖文結(jié)合給大家講解的非常詳細,需要的朋友快來跟著小編一起來學習吧

Buffer Pool 和 DML 的關(guān)系

InnoDB中的「Buffer Pool」除了在查詢時起到提高效率作用,同樣,在insert、update、delete這些DML操作時為了減少和磁盤的頻繁交互,也會將這些更新先在Buffer Pool中緩存的數(shù)據(jù)頁進行操作,隨后將這些有更新的「臟頁」刷到磁盤中。

這個時候就涉及到一個問題:如果MySQL服務宕機了,這些在內(nèi)存中更新的數(shù)據(jù)會不會丟失?

答案是一定會存在丟失現(xiàn)象的,只不過MySQL做到了盡量不讓數(shù)據(jù)丟失。接下來來看一下MySQL是怎么做的。

這里還是把結(jié)構(gòu)圖貼一下,方便下面介紹時看圖理解。

在這里插入圖片描述

DML操作流程

加載數(shù)據(jù)頁

通過上文可以知道,行記錄是在數(shù)據(jù)頁中,所以,當InnoDB接收到DML操作請求后,還是會去找「數(shù)據(jù)頁」,查找的過程跟上文查詢行記錄流程是一樣。這里說一下,insert的請求會根據(jù)主鍵索引去找數(shù)據(jù)頁,update、delete根據(jù)查詢條件去找數(shù)據(jù)頁,總之「數(shù)據(jù)頁」要加載到「Buffer Pool」之后才會進行下一步操作。

更新記錄

定位到數(shù)據(jù)頁后,insert操作就是往數(shù)據(jù)頁中添加一行記錄,delete是標記一下行記錄的‘刪除標記’,而update則是先刪除再添加,這是因為存在可變長的字段類型,比如varchar,每次更新時,這種類型的數(shù)據(jù)占用內(nèi)存是不固定的,所以先刪除再添加。

這里的刪除標記是行記錄的字段,也就是除了業(yè)務字段數(shù)據(jù),InnoDB默認為每行記錄添加的字段,所以一個行記錄大概如下圖,這也是之前提到過的「行格式」。

在這里插入圖片描述

找到數(shù)據(jù)頁并且更新記錄之后DML操作就算完成了,但是還沒有落地到磁盤。

這個時候直接刷新到磁盤視為完成不可以嗎?

數(shù)據(jù)持久化方案

可以是可以,但是如果每次的DML操作都要將一個16KB的數(shù)據(jù)頁刷到磁盤,其效率是極低的,估計也就沒有人用MySQL了。但是如果不刷新到磁盤,就會發(fā)生MySQL服務宕機數(shù)據(jù)會丟失現(xiàn)象。MySQL在這里的處理方案是:

  • 等待合適的時機將批量的「臟頁」異步刷新到磁盤。
  • 先快速將更新的記錄以日志的形式刷新到磁盤。

先看第一點,什么時候是合適的時機?

合適的時機刷盤

當「臟頁」在「Buffer Pool」中達到某個閾值的時候,InnoDB會將這些臟頁刷新到磁盤中。這個閾值可以通過 innodb_max_dirty_pages_pct 這個參數(shù)查看或設置,相關(guān)命令如下:

-- 查看臟頁刷新閾值
show variables like 'innodb_max_dirty_pages_pct'
-- 在線設置臟頁刷新閾值,當臟頁在Buffer Pool占用70%的時候刷新
SET GLOBAL innodb_max_dirty_pages_pct = 70

在這里插入圖片描述

當然,這個合適的時機只是為了減少與磁盤的交互,用來提高性能的,并不能確保數(shù)據(jù)不丟失。

雙寫機制

在刷新「臟頁」這里還有一個非常重要的注意事項就是:因為InnoDB的頁大小為16KB,而一般操作系統(tǒng)的頁大小為4KB。意味著InnoDB將這些「臟頁」向磁盤刷新時,在操作系統(tǒng)層面會被分成4個4KB的頁,這樣的話,如果其中有一頁因為MySQL宕機或者其他異常導致沒有成功刷新到磁盤,就會出現(xiàn)「頁損壞現(xiàn)象」,數(shù)據(jù)也就不完整了。

在這里插入圖片描述

所以InnoDB在這里采用的雙寫機制,在將這些「臟頁」刷新到磁盤之前先會往結(jié)構(gòu)圖中的「Doublewrite Buffer」中寫入,隨后再刷新到對應的表空間中,當出現(xiàn)故障時就可以通過雙寫緩沖區(qū)進行恢復。

向「Doublewrite Buffer」就不會發(fā)生「頁損壞現(xiàn)象」?

Doublewrite Buffer」的大小是獨立且固定的,不是基于頁的大小來劃分的。所以不受操作系統(tǒng)中的頁大小限制,也不會發(fā)生「頁損壞現(xiàn)象」。并且先以順序IO的方式向「Doublewrite Buffer」寫入數(shù)據(jù)頁,再以隨機IO異步刷新到表空間這種方式還可以提高寫入性能。

在這里插入圖片描述

再看第二點,為什么以日志的形式先刷新到磁盤?

日志先行機制

在「Buffer Pool」中更新完數(shù)據(jù)頁后,由于不會及時將這些「臟頁」刷新到磁盤,為了避免數(shù)據(jù)丟失,會將本次的DML操作向「Log Buffer」中寫一份并且刷新到磁盤中,相比16KB的數(shù)據(jù)頁來說,這個數(shù)據(jù)量會小很多,而且寫入日志文件時是追加操作,屬于順序IO,效率較高。如下圖,哪種方式寫入效率更高是顯而易見的。

在這里插入圖片描述

這里說的日志文件就是經(jīng)常會聽到的「Redo Log」,即使MySQL宕機了,通過磁盤的redolog,也可以在MySQL啟動時盡可能的將數(shù)據(jù)恢復到宕機之前樣子。當然,還有「Undo Log」,因為對本文重點沒有直接影響,所以不對此展開說明。

這種日志先行(WAL)的機制也是MySQL用于提高效率和保障數(shù)據(jù)可靠的一種方式。

為什么是盡可能的恢復?

日志刷盤機制

因為「Log Buffer」中的日志數(shù)據(jù)什么時候向磁盤刷新則是由 innodb_flush_log_at_trx_commitinnodb_flush_log_at_timeout 這兩個參數(shù)決定的。

  • innodb_flush_log_at_trx_commit默認為1,也就是每次事務提交后就會刷新到磁盤。
  • innodb_flush_log_at_trx_commit設置為0時,則不會根據(jù)事務提交來刷新,而是根據(jù)innodb_flush_log_at_timeout設置的時間定時刷新,這個時間默認為1秒。
  • innodb_flush_log_at_trx_commit設置為2時,僅將日志寫入操作系統(tǒng)中的緩存中,隨后跟隨根據(jù)innodb_flush_log_at_timeout定時刷新。

如果在MySQL服務宕機的時候,「Log Buffer」中的日志沒有刷新到磁盤,這部分數(shù)據(jù)也是會丟失的,在重啟后也不會恢復。所以如果不想丟失數(shù)據(jù),在性能還可以的情況下,盡量將innodb_flush_log_at_trx_commit設置為1。

「redo log」是怎么恢復數(shù)據(jù)的?

Redo Log 恢復數(shù)據(jù)

首先,redo log會記錄DML的操作類型、數(shù)據(jù)的表空間、數(shù)據(jù)頁以及具體操作內(nèi)容,以 insert into t1(1,'hi')為例,對應的redo log內(nèi)容大概這樣的

在這里插入圖片描述

假如 innodb_flush_log_at_trx_commit 的值為1,那么當該DML操作事務提交后,就會將 redo log 刷新到磁盤。成功刷新到磁盤后,就可以視為數(shù)據(jù)被寫入成功。

此時如果「臟頁」還沒刷新到磁盤便宕機,那么在下次MySQL啟動時便去加載redo log,如果redo log存在數(shù)據(jù)則意味著需要恢復數(shù)據(jù)。這個時候就可以通過redo log中的內(nèi)容重新構(gòu)建「臟頁」,從而恢復到宕機之前的狀態(tài)。

怎么構(gòu)建「臟頁」呢?

其實在每次的redo log寫入時都會記錄一個「LSN(log sequence number)」,同時這個值在「數(shù)據(jù)頁」中記錄最后一次被修改的日志序列位置。MySQL在啟動時通過LSN來對比 redo log 和數(shù)據(jù)頁,如果數(shù)據(jù)頁中的LSN小于 redo log 的LSN,則會將該數(shù)據(jù)頁加載到「Buffer Pool」,然后根據(jù) redo log 的內(nèi)容構(gòu)建出「臟頁」,等待下次刷新到磁盤,數(shù)據(jù)也就恢復了。如下圖

在這里插入圖片描述

注意:這個恢復的過程重點在redo上,實際上還涉及到「Change Buffer」、「Undo Log」等操作,這里沒有展開說明。

「Doublewrite Buffer」和「redo log」都是恢復數(shù)據(jù)的,不沖突嗎?

不沖突,「Doublewrite Buffer」是對「頁損壞現(xiàn)象」的整個數(shù)據(jù)頁進行恢復,Redo Log只能對某次的DML操作進行恢復。

總結(jié)

InnoDB通過以上的操作可以盡可能的保證MySQL不丟失數(shù)據(jù),最后再總結(jié)一下MySQL是如何保障數(shù)據(jù)不丟失的:

  • 為了避免頻繁與磁盤交互,每次DML操作先在「Buffer Pool」中的緩存頁中執(zhí)行,緩存頁有更新之后便成為「臟頁」,隨后根據(jù)innodb_max_dirty_pages_pct這個參數(shù)將「臟頁」刷新到磁盤。
  • 因為「臟頁」在刷新到磁盤之前可能會存在MySQL宕機等異常行為導致數(shù)據(jù)丟失,所以MySQL采用日志先行(WAL)機制,將DML操作以日志的形式進行記錄到「Redo Log」中,隨后根據(jù)innodb_flush_log_at_trx_commitinnodb_flush_log_at_timeout這兩個參數(shù)將「Redo Log」刷新到磁盤,以便恢復。
  • 在向磁盤刷新「臟頁」時,為了避免發(fā)生「頁損壞」現(xiàn)象,InnoDB采用雙寫機制,先將這些臟頁順序?qū)懭搿?strong>Doublewrite Buffer」中,隨后再將數(shù)據(jù)頁異步刷新到各個表空間中,這種方式既能提高寫入效率,又可以保障數(shù)據(jù)的完整性。
  • 如果在「臟頁」刷新到磁盤之前,MySQL宕機了,那么會在下次啟動時通過 redo log 將臟頁構(gòu)建出來,做到數(shù)據(jù)恢復。
  • 通過以上步驟,MySQL做到了盡可能的不丟失數(shù)據(jù)。

以上就是MySQL保證數(shù)據(jù)不丟失的方案詳解的詳細內(nèi)容,更多關(guān)于MySQL保證數(shù)據(jù)不丟失的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • mysql中如何去除小數(shù)點后面多余的0

    mysql中如何去除小數(shù)點后面多余的0

    這篇文章主要介紹了mysql 中去除小數(shù)點后面多余的0的方法 ,需要的朋友可以參考下
    2014-03-03
  • MySQL插入數(shù)據(jù)insert?ignore語法重復數(shù)據(jù)自動忽略

    MySQL插入數(shù)據(jù)insert?ignore語法重復數(shù)據(jù)自動忽略

    這篇文章主要給大家介紹了關(guān)于MySQL插入數(shù)據(jù)insert?ignore語法重復數(shù)據(jù)自動忽略的相關(guān)資料,最近工作中使用到了insert ignore into語法,感覺這個語法還是挺有用的,就記錄下來做個總結(jié),需要的朋友可以參考下
    2023-08-08
  • MySQL?排序規(guī)則Collation實例詳解

    MySQL?排序規(guī)則Collation實例詳解

    本文將從基礎(chǔ)概念出發(fā),詳解排序規(guī)則的作用、與字符集的關(guān)系、查看與配置方法,并通過實際案例說明其對查詢結(jié)果的影響,幫助開發(fā)者精準控制數(shù)據(jù)匹配行為,感興趣的朋友一起看看吧
    2025-07-07
  • MySQL thread_stack連接線程的優(yōu)化

    MySQL thread_stack連接線程的優(yōu)化

    當有新的連接請求時,MySQL首先會檢查Thread Cache中是否存在空閑連接線程,如果存在則取出來直接使用,如果沒有空閑連接線程,才創(chuàng)建新的連接線程
    2017-04-04
  • 開源MySQL高效數(shù)據(jù)倉庫解決方案:Infobright詳細介紹

    開源MySQL高效數(shù)據(jù)倉庫解決方案:Infobright詳細介紹

    這篇文章主要介紹了開源MySQL高效數(shù)據(jù)倉庫解決方案:Infobright詳細介紹,本文講解了Infobright特征、Infobright的價值、Infobright的適用場景、與MySQL對比等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • Mysql事物的持久性及原子性詳解

    Mysql事物的持久性及原子性詳解

    這段文章詳細介紹了數(shù)據(jù)庫事務的ACID特性,重點闡述了原子性和持久性的實現(xiàn)機制,包括CommitLogging和WAL機制,通過具體案例和代碼演示,深入解析了數(shù)據(jù)庫如何確保事務的正確執(zhí)行,感興趣的朋友跟隨小編一起看看吧
    2026-05-05
  • MySQL查詢?nèi)罩綠eneral Log的配置與作用

    MySQL查詢?nèi)罩綠eneral Log的配置與作用

    本文將詳細介紹 General Log的配置方法、查看方式、核心作用及使用注意事項,幫助運維和開發(fā)人員高效利用該日志工具,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2026-04-04
  • MySQL中int最大值深入講解

    MySQL中int最大值深入講解

    這篇文章主要給大家介紹了關(guān)于MySQL中int最大值的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-02-02
  • MySQL字符之char、varchar類型簡析

    MySQL字符之char、varchar類型簡析

    varchar和char是MySQL中的兩種數(shù)據(jù)類型,都是用來存儲字符串的,下面這篇文章主要給大家介紹了關(guān)于MySQL字符之char、varchar類型的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • MySQL的鎖機制使用詳解

    MySQL的鎖機制使用詳解

    這篇文章主要介紹了MySQL的鎖機制使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04

最新評論

洪江市| 奇台县| 陵川县| 龙川县| 广德县| 北川| 蕉岭县| 定南县| 营口市| 饶平县| 河源市| 基隆市| 海门市| 龙州县| 平遥县| 无为县| 田林县| 青海省| 安图县| 绥中县| 怀宁县| 莱阳市| 崇州市| 盐池县| 怀安县| 海淀区| 阜康市| 沂源县| 黑山县| 千阳县| 吉首市| 家居| 沾益县| 湾仔区| 江北区| 资兴市| 汉沽区| 奇台县| 永定县| 伊宁县| 孟州市|