自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL存儲底層技術(shù):InnoDB底層原理解讀

存儲 存儲軟件
很多文章都是直接開始介紹有哪些存儲引擎,并沒有去介紹存儲引擎本身。那么究竟什么是存儲引擎?不知道大家有沒有想過,MySQL是如何存儲我們丟進(jìn)去的數(shù)據(jù)的?

[[412687]]

存儲引擎

很多文章都是直接開始介紹有哪些存儲引擎,并沒有去介紹存儲引擎本身。那么究竟什么是存儲引擎?不知道大家有沒有想過,MySQL是如何存儲我們丟進(jìn)去的數(shù)據(jù)的?

其實存儲引擎也很簡單,我認(rèn)為就是一種存儲解決方案,實現(xiàn)了新增數(shù)據(jù)、更新數(shù)據(jù)和建立索引等等功能。

有哪些已有的存儲引擎可以讓我們選擇呢?

InnoDB、MyISAM、Memory、CSV、Archive、Blackhole、Merge、Federated、Example

種類很多,但是常用的存儲引擎目前就只有InnoDB和MyISAM,我也會著重來介紹這兩種存儲引擎。

InnoDB是目前使用最廣的MySQL存儲引擎,MySQL從5.5版本開始InnoDB就已經(jīng)是默認(rèn)的存儲引擎了。那你知道為什么InnoDB被廣泛的使用呢?先把這個問題放一放,我們先來了解一下InnoDB存儲引擎的底層原理。

InnoDB的內(nèi)存架構(gòu)主要分為三大塊,緩沖池(Buffer Pool)、重做緩沖池(Redo Log Buffer)和額外內(nèi)存池

緩沖池

InnoDB為了做數(shù)據(jù)的持久化,會將數(shù)據(jù)存儲到磁盤上。但是面對大量的請求時,CPU的處理速度和磁盤的IO速度之間差距太大,為了提高整體的效率, InnoDB引入了緩沖池。

當(dāng)有請求來查詢數(shù)據(jù)時,如果緩存池中沒有,就會去磁盤中查找,將匹配到的數(shù)據(jù)放入緩存池中。同樣的,如果有請求來修改數(shù)據(jù),MySQL并不會直接去修改磁盤,而是會修改已經(jīng)在緩沖池的頁中的數(shù)據(jù),然后再將數(shù)據(jù)刷回磁盤,這就是緩沖池的作用,加速讀,加速寫,減少與磁盤的IO交互。

緩沖池說白了就是把磁盤中的數(shù)據(jù)丟到內(nèi)存,那既然是內(nèi)存就會存在沒有內(nèi)存空間可以分配的情況。所以緩沖池采用了LRU算法,在緩沖池中沒有空閑的頁時,來進(jìn)行頁的淘汰。但是采用這種算法會帶來一個問題叫做緩沖池污染。

當(dāng)你在進(jìn)行批量掃描甚至全表掃描時,可能會將緩沖池中的熱點(diǎn)頁全部替換出去。這樣一來可能會導(dǎo)致MySQL的性能斷崖式下降。所以InnoDB對LRU做了一些優(yōu)化,規(guī)避了這個問題。

MySQL采用日志先行,在真正寫數(shù)據(jù)之前,會首先記錄一個日志,叫Redo Log,會定期的使用CheckPoint技術(shù)將新的Redo Log刷入磁盤,這個后面會講。

除了數(shù)據(jù)之外,里面還存儲了索引頁、Undo頁、插入緩沖、自適應(yīng)哈希索引、InnoDB鎖信息和數(shù)據(jù)字典。下面選幾個比較重要的來簡單聊一聊。

插入緩沖

插入緩沖針對的操作是更新或者插入,我們考慮最壞的情況,那就是需要更新的數(shù)據(jù)都不在緩沖池中。那么此時會有下面兩種方案。

來一條數(shù)據(jù)就直接寫入磁盤等數(shù)據(jù)達(dá)到某個閾值(例如50條)才批量的寫入磁盤

很明顯,第二種方案要好一點(diǎn),減少了與磁盤IO的交互。

兩次寫

鑒于都聊到了插入緩沖,我就不得不需要提一嘴兩次寫,因為我認(rèn)為這兩個InnoDB的特性是相輔相成的。

插入緩沖提高了MySQL的性能,而兩次寫則在此基礎(chǔ)上提高了數(shù)據(jù)的可靠性。我們知道,當(dāng)數(shù)據(jù)還在緩沖池中的時候,當(dāng)機(jī)器宕機(jī)了,發(fā)生了寫失效,有Redo Log來進(jìn)行恢復(fù)。但是如果是在從緩沖池中將數(shù)據(jù)刷回磁盤的時候宕機(jī)了呢?

這種情況叫做部分寫失效,此時重做日志就無法解決問題。

 

在刷網(wǎng)頁時,并不是直接刷入磁盤,而是copy到內(nèi)存中的Doublewrite Buffer中,然后再拷貝至磁盤共享表空間(你可以就理解為磁盤)中,每次寫入1M,等copy完成后,再將Doublewrite Buffer中的頁寫入磁盤文件。

有了兩次寫機(jī)制,即使在刷臟頁時宕機(jī)了,在實例恢復(fù)的時候也可以從共享表空間中找到Doublewrite Buffer的頁副本,直接將其覆蓋原來的數(shù)據(jù)頁即可。

自適應(yīng)哈希索引

自適應(yīng)索引就跟JVM在運(yùn)行過程中,會動態(tài)的把某些熱點(diǎn)代碼編譯成Machine Code一樣,InnoDB會監(jiān)控對所有索引的查詢,對熱點(diǎn)訪問的頁建立哈希索引,以此來提升訪問速度。

你可能多次看到了一個關(guān)鍵字頁,接下來那我們就來聊一下頁是什么?

頁,是InnoDB中數(shù)據(jù)管理的最小單位。當(dāng)我們查詢數(shù)據(jù)時,其是以頁為單位,將磁盤中的數(shù)據(jù)加載到緩沖池中的。同理,更新數(shù)據(jù)也是以頁為單位,將我們對數(shù)據(jù)的修改刷回磁盤。每頁的默認(rèn)大小為16k,每頁中包含了若干行的數(shù)據(jù),頁的結(jié)構(gòu)如下圖所示。

 

不用太糾結(jié)每個區(qū)是干嘛的,我們只需要知道這樣設(shè)計的好處在哪兒。每一頁的數(shù)據(jù),可以通過FileHeader中的上一頁和下一頁的數(shù)據(jù),頁與頁之間可以形成雙向鏈表。因為在實際的物理存儲上,數(shù)據(jù)并不是連續(xù)存儲的。你可以把它理解成G1的Region在內(nèi)存中的分布。

而一頁中所包含的行數(shù)據(jù),行與行之間則形成了單向鏈表。我們存入的行數(shù)據(jù)最終會到User Records中,當(dāng)然最初User Records并不占據(jù)任何存儲空間。隨著我們存入的數(shù)據(jù)越來越多,User Records會越來越大,F(xiàn)ree Space的空間會越來越小,直到被占用完,就會申請新的數(shù)據(jù)頁。

User Records中的數(shù)據(jù),是按照主鍵id來進(jìn)行排序的,當(dāng)我們按照主鍵來進(jìn)行查找時,會沿著這個單向鏈表一直往后找,

重做日志緩沖

上面聊過,InnoDB中緩沖池中的頁數(shù)據(jù)更新會先于磁盤數(shù)據(jù)更新的,InnoDB也會采用日志先行(Write Ahead Log)策略來刷新數(shù)據(jù),什么意思呢?當(dāng)事務(wù)開始時,會先記錄Redo Log到Redo Log Buffer中,然后再更新緩沖池頁數(shù)據(jù)。

Redo Log Buffer中的數(shù)據(jù)會按照一定的頻率寫到重做日志中去。被更改過的頁就會被標(biāo)記成臟頁,InnoDB會根據(jù)CheckPoint機(jī)制來將臟頁刷到磁盤。

日志

上面提到了Redo log,這一小節(jié)就專門來講一講日志,日志分為如下兩個維度。

  • MySQL層面
  • InnoDB層面

MySQL日志

MySQL的日志可以分為錯誤日志、二進(jìn)制文件、查詢?nèi)罩竞蜐M查詢?nèi)罩尽?/p>

  • 錯誤日志 很好理解,就是服務(wù)運(yùn)行過程中發(fā)生的嚴(yán)重錯誤日志。當(dāng)我們的數(shù)據(jù)庫無法啟動時,就可以來這里看看具體不能啟動的原因是什么
  • 二進(jìn)制文件 它有另外一個名字你應(yīng)該熟悉,叫Binlog,其記錄了對數(shù)據(jù)庫所有的更改。
  • 查詢?nèi)罩?記錄了來自客戶端的所有語句
  • 慢查詢?nèi)罩? 這里記錄了所有響應(yīng)時間超過閾值的SQL語句,這個閾值我們可以自己設(shè)置,參數(shù)為long_query_time,其默認(rèn)值為10s,且默認(rèn)是關(guān)閉的狀態(tài),需要手動的打開。

InnoDB日志

InnoDB日志就只有兩種,Redo Log和Undo Log,

  • Redo Log 重做日志,用于記錄事務(wù)操作的變化,且記錄的是修改之后的值。不管事務(wù)是否提交都會記錄下來。例如在更新數(shù)據(jù)時,會先將更新的記錄寫到Redo Log中,再更新緩存中頁中的數(shù)據(jù)。然后按照設(shè)置的更新策略,將內(nèi)存中的數(shù)據(jù)刷回磁盤。
  • Undo Log 記錄的是記錄的事務(wù)開始之前的一個版本,可用于事務(wù)失敗之后發(fā)生的回滾。

Redo Log記錄的是具體某個數(shù)據(jù)頁上的修改,只能在當(dāng)前Server使用,而Binlog可以理解為可以給其他類型的存儲引擎使用。這也是Binlog的一個重要作用,那就是主從復(fù)制,另外一個作用是數(shù)據(jù)恢復(fù)。

上面提到過,Binlog中記錄了所有對數(shù)據(jù)庫的修改,其記錄日志有三種格式。分別是Statement、Row和MixedLevel。

  • Statement 記錄所有會修改數(shù)據(jù)的SQL,其只會記錄SQL,并不需要記錄下這個SQL影響的所有行,減少了日志量,提高了性能。但是由于只是記錄執(zhí)行語句,不能保證在Slave節(jié)點(diǎn)上能夠正確執(zhí)行,所以還需要額外的記錄一些上下文信息
  • Row 只保存被修改的記錄,與Statement只記錄執(zhí)行SQL來比較,Row會產(chǎn)生大量的日志。但是Row不用記錄上下文信息了,只需要關(guān)注被改成啥樣就行。
  • MixedLevel 就是Statement和Row混合使用。

具體使用哪種日志,需要根據(jù)實際情況來決定。例如一條UPDATE語句更新了很多的數(shù)據(jù),采用Statement會更加節(jié)省空間,但是相對的,Row會更加的可靠。

InnoDB和MyISAM的區(qū)別

由于MyISAM并不常用,我也不打算去深究其底層的一些原理和實現(xiàn)。我們在這里簡單的對比一下這兩個存儲引擎的區(qū)別就好。我們分點(diǎn)來一點(diǎn)點(diǎn)描述。

  • 事務(wù) InnoDB支持事務(wù)、回滾、事務(wù)安全和崩潰恢復(fù)。而MyISAM不支持,但查詢的速度要比InnoDB更快
  • 主鍵 InnoDB規(guī)定,如果沒有設(shè)置主鍵,就自動的生成一個6字節(jié)的主鍵,而MyISAM允許沒有任何索引和主鍵的存在,索引就是行的地址
  • 外鍵 InnoDB支持外鍵,而MyISAM不支持
  • 表鎖 InnoDB支持行鎖和表鎖,而MyISAM只支持表鎖
  • 全文索引 InnoDB不支持全文索引,但是可以用插件來實現(xiàn)相應(yīng)的功能,而MyISAM是本身就支持全本索引
  • 行數(shù) InnoDB獲取行數(shù)時,需要掃全表。而MyISAM保存了當(dāng)前表的總行數(shù),直接讀取即可。

所以,簡單總結(jié)一下,MyISAM只適用于查詢大于更新的場景,如果你的系統(tǒng)查詢的情況占絕大多數(shù)(例如報表系統(tǒng))就可以使用MyISAM來存儲,除此之外,都建議使用InnoDB。

End

由于時間的原因,本文只是簡單的聊了聊InnoDB的整體架構(gòu),并沒有很深入的去聊某些點(diǎn)。例如InnoDB是如何改進(jìn)來解決緩沖池污染的,其算法具體是什么,checkpoint是如何工作的等等,只是做一個簡單的了解,之后如果有時間的話再細(xì)聊。

 

責(zé)任編輯:武曉燕 來源: 今日頭條
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號