本篇文章給大家?guī)?lái)了關(guān)于mysql的相關(guān)知識(shí),其中主要介紹了關(guān)于存儲(chǔ)引擎InnoDB架構(gòu)的相關(guān)內(nèi)容,InnoDB是MySQL的默認(rèn)引擎,一個(gè)支持事務(wù)安全的存儲(chǔ)引擎,下面一起來(lái)看一下,希望對(duì)大家有幫助。
程序員必備接口測(cè)試調(diào)試工具:立即使用
Apipost = Postman + Swagger + Mock + Jmeter
Api設(shè)計(jì)、調(diào)試、文檔、自動(dòng)化測(cè)試工具
后端、前端、測(cè)試,同時(shí)在線協(xié)作,內(nèi)容實(shí)時(shí)同步
推薦學(xué)習(xí):mysql視頻教程
目前MySQL8.x版本數(shù)據(jù)庫(kù)已經(jīng)支持了很多存儲(chǔ)引擎了,但是一般我們常用的就幾種,容易形成思維固化不會(huì)輕易采取其他存儲(chǔ)引擎,從而錯(cuò)失很多優(yōu)化存儲(chǔ)的功能。因此對(duì)現(xiàn)支持的九種數(shù)據(jù)庫(kù)存儲(chǔ)引擎的功能有個(gè)清楚的理解是個(gè)值得學(xué)習(xí)的事情。本篇文章將這八種數(shù)據(jù)庫(kù)存儲(chǔ)引擎的功能和作用以及使用場(chǎng)景都講清楚。
此系列文章將被納入我的專欄一文速學(xué)SQL各類數(shù)據(jù)庫(kù)操作,基本覆蓋到使用SQL處理日常業(yè)務(wù)以及常規(guī)的查詢建庫(kù)分析以及復(fù)雜操作方方面面的問(wèn)題。從基礎(chǔ)的建庫(kù)建表逐步入門(mén)到處理各類數(shù)據(jù)庫(kù)復(fù)雜操作,以及專業(yè)的SQL常用函數(shù)講解都花費(fèi)了大量時(shí)間和心思創(chuàng)作,如果大家有需要從事數(shù)據(jù)分析或者數(shù)據(jù)開(kāi)發(fā)的朋友推薦訂閱專欄,將在第一時(shí)間學(xué)習(xí)到最實(shí)用常用的知識(shí)。此篇博客篇幅較長(zhǎng),值得細(xì)讀實(shí)踐一番,我會(huì)將精華部分挑出細(xì)講實(shí)踐。博主會(huì)長(zhǎng)期維護(hù)博文,有錯(cuò)誤或者疑惑可以在評(píng)論區(qū)指出,感謝大家的支持。
一、支持的存儲(chǔ)引擎
進(jìn)入MySQL的數(shù)據(jù)庫(kù)查看存儲(chǔ)引擎就可以看到MySQL數(shù)據(jù)庫(kù)所有支持的存儲(chǔ)引擎:
SHOW ENGINES
目前有一個(gè)引擎Federated不支持,我們只需要清楚其他八種數(shù)據(jù)庫(kù)存儲(chǔ)就好。
MySQL中常見(jiàn)的數(shù)據(jù)庫(kù)引擎有MyISAM、InnoDB、Memory。那么我們就先清楚這三種引擎。
二、InnoDB引擎
InnoDB是MySQL的默認(rèn)引擎,一個(gè)支持事務(wù)安全的存儲(chǔ)引擎。mysql中數(shù)據(jù)是存儲(chǔ)在物理磁盤(pán)上的,而真正的數(shù)據(jù)處理又是在內(nèi)存中執(zhí)行的。由于磁盤(pán)的讀寫(xiě)速度非常慢,如果每次操作都對(duì)磁盤(pán)進(jìn)行頻繁讀寫(xiě)的話,那么性能就會(huì)非常差。
為了上述問(wèn)題,InnoDB將數(shù)據(jù)劃分為若干頁(yè),以頁(yè)作為磁盤(pán)與內(nèi)存交互的基本單位,一般頁(yè)的大小為16KB。這樣的話,一次性至少讀取1頁(yè)數(shù)據(jù)到內(nèi)存中或者將1頁(yè)數(shù)據(jù)寫(xiě)入磁盤(pán)。通過(guò)減少內(nèi)存與磁盤(pán)的交互次數(shù),從而提升性能。
這本質(zhì)上就是一種典型的緩存設(shè)計(jì)思想,一般緩存的設(shè)計(jì)基本都是從時(shí)間維度或者空間維度進(jìn)行考量的:
-
時(shí)間維度:如果一條數(shù)據(jù)正在在被使用,那么在接下來(lái)一段時(shí)間內(nèi)大概率還會(huì)再被使用??梢哉J(rèn)為熱點(diǎn)數(shù)據(jù)緩存都屬于這種思路的實(shí)現(xiàn)。
-
空間維度:如果一條數(shù)據(jù)正在在被使用,那么存儲(chǔ)在它附近的數(shù)據(jù)大概率也會(huì)很快被使用。InnoDB的數(shù)據(jù)頁(yè)和操作系統(tǒng)的頁(yè)緩存則是這種思路的體現(xiàn)。
下面是官方的InnoDB引擎結(jié)構(gòu)圖,主要分為內(nèi)存結(jié)構(gòu)和磁盤(pán)結(jié)構(gòu)兩大部分。
內(nèi)存結(jié)構(gòu)主要包括Buffer Pool、Change Buffer、Adaptive Hash Index和Log Buffer四大組件。
1.Buffer Pool
Buffer Pool由包含數(shù)據(jù)、索引、insert buffer ,adaptive hash index,lock 信息及數(shù)據(jù)字典。緩沖池,簡(jiǎn)稱BP。BP以Page頁(yè)為單位,默認(rèn)大小16K,BP的底層采用鏈表數(shù)據(jù)結(jié)構(gòu)管理Page。在InnoDB訪問(wèn)表記錄和索引時(shí)會(huì)在Page頁(yè)中緩存,以后使用可以減少磁盤(pán)IO操作,提升效率。
緩沖池簡(jiǎn)單來(lái)說(shuō)就是一塊內(nèi)存區(qū)域,通過(guò)內(nèi)存的速度來(lái)彌補(bǔ)磁盤(pán)速度較慢對(duì)數(shù)據(jù)庫(kù)性能的影響。在數(shù)據(jù)庫(kù)中進(jìn)行讀取頁(yè)的操作,首先將從磁盤(pán)讀到的頁(yè)存放在緩沖池中,這個(gè)過(guò)程稱為將頁(yè)"FIX"在緩沖池中。下一次再讀取相同的頁(yè)時(shí),首先判斷該頁(yè)是否在緩沖池中。若在緩沖池中,稱該頁(yè)在緩沖池中被命中。直接讀取該頁(yè)。否則讀取磁盤(pán)上的頁(yè)。對(duì)于數(shù)據(jù)庫(kù)中頁(yè)的修改操作,則首先修改在緩沖池中的頁(yè),然后再以一定的頻率刷新到磁盤(pán)上。這里需要注意的是,頁(yè)從緩沖池刷新回磁盤(pán)的操作并不是每次頁(yè)發(fā)生更新時(shí)觸發(fā),而是通過(guò)一種稱為Checkpoint的機(jī)制刷新回磁盤(pán)。同樣這也是為了提高數(shù)據(jù)庫(kù)的整體性能。
傳統(tǒng)LUR算法
緩沖池是通過(guò)LRU(Latest Recent Used,最近最少使用)算法來(lái)進(jìn)行管理的,即最頻繁使用的頁(yè)在LRU列表的最前段,而最少使用的頁(yè)在LRU列表的尾端,當(dāng)緩沖池不能存放新讀取到的頁(yè)時(shí),首先釋放LRU列表尾端的頁(yè):
(1)頁(yè)已經(jīng)在緩沖池里,那就只做“移至”LRU頭部的動(dòng)作,而沒(méi)有頁(yè)被淘汰;
(2)頁(yè)不在緩沖池里,除了做“放入”LRU頭部的動(dòng)作,還要做“淘汰”LRU尾部頁(yè)的動(dòng)作;
但是InnoDB的LUR算法并不是傳統(tǒng)的LUR算法。
這里有兩個(gè)問(wèn)題:
(1)預(yù)讀失效;
(2)緩沖池污染;
我們先了解什么是預(yù)讀;
預(yù)讀
磁盤(pán)讀寫(xiě),并不是按需讀取,而是按頁(yè)讀取,一次至少讀一頁(yè)數(shù)據(jù)(一般是4K),如果未來(lái)要讀取的數(shù)據(jù)就在頁(yè)中,就能夠省去后續(xù)的磁盤(pán)IO,提高效率。數(shù)據(jù)訪問(wèn),通常都遵循“集中讀寫(xiě)”的原則,使用一些數(shù)據(jù),大概率會(huì)使用附近的數(shù)據(jù),這就是所謂的“局部性原理”,它表明提前加載是有效的,確實(shí)能夠減少磁盤(pán)IO。
預(yù)讀失效
由于預(yù)讀(Read-Ahead),提前把頁(yè)放入了緩沖池,但最終MySQL并沒(méi)有從頁(yè)中讀取數(shù)據(jù),稱為預(yù)讀失效。
要優(yōu)化預(yù)讀失效,思路是:
(1)讓預(yù)讀失敗的頁(yè),停留在緩沖池LRU里的時(shí)間盡可能短;
(2)讓真正被讀取的頁(yè),才挪到緩沖池LRU的頭部;
以保證,真正被讀取的熱數(shù)據(jù)留在緩沖池里的時(shí)間盡可能長(zhǎng)。
具體方法是:
(1)將LRU分為兩個(gè)部分:
新生代(new sublist)
老生代(old sublist)
(2)新老生代收尾相連,即:新生代的尾(tail)連接著老生代的頭(head);
(3)新頁(yè)(例如被預(yù)讀的頁(yè))加入緩沖池時(shí),只加入到老生代頭部:
如果數(shù)據(jù)真正被讀?。A(yù)讀成功),才會(huì)加入到新生代的頭部
如果數(shù)據(jù)沒(méi)有被讀取,則會(huì)比新生代里的“熱數(shù)據(jù)頁(yè)”更早被淘汰出緩沖池
新老生代改進(jìn)版LRU仍然解決不了緩沖池污染的問(wèn)題。
2.Log Buffer
Log Buffer用來(lái)緩存重做日志。
InnoDB有兩個(gè)非常重要的日志:undo log、redo log
(1)通過(guò)undo log可以看到數(shù)據(jù)較早版本,實(shí)現(xiàn)MVCC,或回滾事務(wù)等功能。
(2)通過(guò)redo log用來(lái)保證事務(wù)持久性。
redo日志緩沖區(qū)是內(nèi)存存儲(chǔ)區(qū)域,用于保存要寫(xiě)入磁盤(pán)上的日志文件的數(shù)據(jù)。日志緩沖區(qū)大小由innodb_log_buffer_size 變量定義,默認(rèn)大小為16MB。
日志緩沖區(qū)的內(nèi)容定期刷新到磁盤(pán)。較大的日志緩沖區(qū)可以運(yùn)行大型事務(wù),而無(wú)需在事務(wù)提交之前將重做日志數(shù)據(jù)寫(xiě)入磁盤(pán)。因此,如果有更新,插入或刪除許多行的事務(wù),則增加日志緩沖區(qū)的大小可以節(jié)省磁盤(pán)I/O。
innodb_flush_log_at_trx_commit :控制如何將日志緩沖區(qū)的內(nèi)容寫(xiě)入并刷新到磁盤(pán)。
innodb_flush_log_at_timeout :控制日志刷新頻率。
如果磁盤(pán)I/O導(dǎo)致性能問(wèn)題,則需要觀察事務(wù),例如涉及許多BLOB條目的事務(wù)。只要InnoDB日志緩沖區(qū)已滿,便會(huì)將其刷新到磁盤(pán),因此增加緩沖區(qū)大小可以減少I(mǎi)/O。
日志文件的缺省數(shù)量為兩個(gè): ib_logfile0 和 ib_logfile1 。
日志具有固定大小,默認(rèn)大小取決于MySQL版本。
3.Adaptive Hash Index
Adaptive Hash Index自適應(yīng)hash索引是一種鍵值對(duì)的存儲(chǔ)結(jié)構(gòu),存儲(chǔ)的是熱點(diǎn)頁(yè)所在的記錄。InnoDB存儲(chǔ)引擎會(huì)自動(dòng)根據(jù)訪問(wèn)的頻率和模式 來(lái)為某些頁(yè)建立哈希索引。
上面的圖就是區(qū)分B+樹(shù)索引和自適應(yīng)hash索引的區(qū)別。 通過(guò)參數(shù)innodb_adaptive_hash_index來(lái)禁用或啟動(dòng)此特性,默認(rèn)為開(kāi)啟。
4.Change Buffer
Change Buffer:MySQL中數(shù)據(jù)分為內(nèi)存和磁盤(pán)兩個(gè)部分;在buffer pool中緩存熱的數(shù)據(jù)頁(yè)和索引頁(yè),減少磁盤(pán)讀;通過(guò)change buffer就是為了緩解磁盤(pán)寫(xiě)的一種手段。
當(dāng)需要更新一個(gè)數(shù)據(jù)頁(yè)時(shí),如果數(shù)據(jù)頁(yè)在內(nèi)存中就直接更新。如果數(shù)據(jù)頁(yè)不在內(nèi)存中。在不影響數(shù)據(jù)一致性的前下,InooDB 會(huì)將這些更新操作緩存在 change buffer 中,這樣就不需要從磁盤(pán)中讀入這個(gè)數(shù)據(jù)頁(yè)了。在下次查詢需要訪問(wèn)這個(gè)數(shù)據(jù)頁(yè)的時(shí)候,將數(shù)據(jù)頁(yè)讀入內(nèi)存,然后執(zhí)行 change buffer 中與這個(gè)頁(yè)有關(guān)的操作。通過(guò)這種方式就能保證這個(gè)數(shù)據(jù)邏輯的正確性。
雖然名字叫作 change buffer,實(shí)際上它是可以持久化的數(shù)據(jù)。也就是說(shuō),change buffer 在內(nèi)存中有拷貝,也會(huì)被寫(xiě)入到磁盤(pán)上(ibdata)。
?將 change buffer 中的操作合并到原數(shù)據(jù)頁(yè),得到最新結(jié)果的過(guò)程稱為 merge。以下情況會(huì)觸發(fā)merge:
-
訪問(wèn)這個(gè)數(shù)據(jù)頁(yè);
-
后臺(tái)master線程會(huì)定期 merge;
-
數(shù)據(jù)庫(kù)緩沖池不夠用時(shí);
-
數(shù)據(jù)庫(kù)正常關(guān)閉時(shí);
-
redo log寫(xiě)滿時(shí);
change buffer就是在非唯一普通索引頁(yè)不在buffer pool中時(shí),對(duì)頁(yè)進(jìn)行了寫(xiě)操作的情況下,先將記錄變更緩沖,等未來(lái)數(shù)據(jù)被讀取時(shí),再將 change buffer 中的操作merge到原數(shù)據(jù)頁(yè)的技術(shù)。在MySQL5.5之前,叫插入緩沖(insert buffer),只針對(duì)insert做了優(yōu)化;現(xiàn)在對(duì)delete和update也有效,叫做寫(xiě)緩沖(change buffer)。
推薦學(xué)習(xí):mysql視頻教程