小編給大家分享一下MySQL中InnoDB存儲(chǔ)引擎是如何設(shè)計(jì)的,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
創(chuàng)新互聯(lián)是一家專注于網(wǎng)站制作、網(wǎng)站建設(shè)與策劃設(shè)計(jì),鼓樓網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:鼓樓等地區(qū)。鼓樓做網(wǎng)站價(jià)格咨詢:18982081108
MySQL 中的兩個(gè)成員 binlog 和 redo log。然而,這只是 MySQL 家族里的兩個(gè)小嘍啰,Mysql 可以做到高性能高可靠,靠的絕對(duì)不只有他們倆。
MySQL 里還有什么其他成員呢?
這其中,最底下的存儲(chǔ)引擎層(Storage Engines),它決定了 MySQL 會(huì)怎樣存儲(chǔ)數(shù)據(jù),怎樣讀取和寫入數(shù)據(jù),也在很大程度上決定了 MySQL 的讀寫性能和數(shù)據(jù)可靠性。
對(duì)于這么重要的一層能力,MySQL 提供了極強(qiáng)的擴(kuò)展性,你可以定義自己要使用什么樣的存儲(chǔ)引擎:InnoDB、MyISAM、MEMORY、CSV,甚至可以自己開發(fā)一個(gè)存儲(chǔ)引擎然后使用它。
通常我們說 Mysql 高性能高可靠,都是指基于 InnoDB 存儲(chǔ)引擎的 Mysql,所以,這一講,先讓我們來看看,除了 redo log,InnoDB 里還有哪些成員,他們都有什么能力,承擔(dān)了什么樣的角色,他們之間又是怎么配合的?
InnoDB 內(nèi)存架構(gòu)
InnoDB 主要分為兩大塊:內(nèi)存和磁盤,讓我們先從內(nèi)存開始。
1、Buffer Pool
正如之前提到的,MySQL 不會(huì)直接去修改磁盤的數(shù)據(jù),因?yàn)檫@樣做太慢了,MySQL 會(huì)先改內(nèi)存,然后記錄 redo log,等有空了再刷磁盤,如果內(nèi)存里沒有數(shù)據(jù),就去磁盤 load。
而這些數(shù)據(jù)存放的地方,就是 Buffer Pool。
我們平時(shí)開發(fā)時(shí),會(huì)用 redis 來做緩存,緩解數(shù)據(jù)庫壓力,其實(shí) MySQL 自己也做了一層類似緩存的東西。
MySQL 是以「頁」(page)為單位從磁盤讀取數(shù)據(jù)的,Buffer Pool 里的數(shù)據(jù)也是如此,實(shí)際上,Buffer Pool 是a linked list of pages,一個(gè)以頁為元素的鏈表。
為什么是鏈表?因?yàn)楹途彺嬉粯樱残枰惶滋蕴惴▉砉芾頂?shù)據(jù)。
Buffer Pool 采用基于 LRU(least recently used) 的算法來管理內(nèi)存。
2、Change Buffer
上面提到過,如果內(nèi)存里沒有對(duì)應(yīng)「頁」的數(shù)據(jù),MySQL 就會(huì)去把數(shù)據(jù)從磁盤里 load 出來,如果每次需要的「頁」都不同,或者不是相鄰的「頁」,那么每次 MySQL 都要去 load,這樣就很慢了。
于是如果 MySQL 發(fā)現(xiàn)你要修改的頁,不在內(nèi)存里,就把你要對(duì)頁的修改,先記到一個(gè)叫 Change Buffer 的地方,同時(shí)記錄 redo log,然后再慢慢把數(shù)據(jù) load 到內(nèi)存,load 過來后,再把 Change Buffer 里記錄的修改,應(yīng)用到內(nèi)存(Buffer Pool)中,這個(gè)動(dòng)作叫做 merge;而把內(nèi)存數(shù)據(jù)刷到磁盤的動(dòng)作,叫 purge:
merge:Change Buffer -> Buffer Pool
purge:Buffer Pool -> Disk
上面是 MySQL 官網(wǎng)對(duì) Change Buffer 的定義,仔細(xì)看的話,你會(huì)發(fā)現(xiàn)里面提到:Change Buffer 只在操作「二級(jí)索引」(secondary index)時(shí)才使用,原因是「聚簇索引」(clustered indexes)必須是「唯一」的,也就意味著每次插入、更新,都需要檢查是否已經(jīng)有相同的字段存在,也就沒有必要使用 Change Buffer 了;另外,「聚簇索引」操作的隨機(jī)性比較小,通常在相鄰的「頁」進(jìn)行操作,比如使用了自增主鍵的「聚簇索引」,那么 insert 時(shí)就是遞增、有序的,不像「二級(jí)索引」,訪問非常隨機(jī)。
3、Adaptive Hash Index
MySQL 索引,不管是在磁盤里,還是被 load 到內(nèi)存后,都是 B+ 樹,B+ 樹的查找次數(shù)取決于樹的深度。你看,數(shù)據(jù)都已經(jīng)放到內(nèi)存了,還不能“一下子”就找到它,還要“幾下子”,這空間犧牲的是不是不太值得?
尤其是那些頻繁被訪問的數(shù)據(jù),每次過來都要走 B+ 樹來查詢,這時(shí)就會(huì)想到,我用一個(gè)指針把數(shù)據(jù)的位置記錄下來不就好了?
這就是「自適應(yīng)哈希索引」(Adaptive Hash Index)。自適應(yīng),顧名思義,MySQL 會(huì)自動(dòng)評(píng)估使用自適應(yīng)索引是否值得,如果觀察到建立哈希索引可以提升速度,則建立。
4、Log Buffer
Log Buffer 里的 redo log,會(huì)被刷到磁盤里。
Operating System Cache
在內(nèi)存和磁盤之間,你看到 MySQL 畫了一層叫做 Operating System Cache 的東西,其實(shí)這個(gè)不屬于 InnoDB 的能力,而是操作系統(tǒng)為了提升性能,在磁盤前面加的一層高速緩存,這里不展開細(xì)講,感興趣的同學(xué)可以參考下維基百科:Page Cache
InnoDB 磁盤架構(gòu)
磁盤里有什么呢?除了表結(jié)構(gòu)定義和索引,還有一些為了高性能和高可靠而設(shè)計(jì)的角色,比如 redo log、undo log、Change Buffer,以及 Doublewrite Buffer 等等。
1、表空間(Tablespaces)
可以看到,Tablespaces 分為五種:The System Tablespace;File-Per-Table Tablespaces;General Tablespace;Undo Tablespaces;Temporary Tablespaces。
其中,我們平時(shí)創(chuàng)建的表的數(shù)據(jù),可以存放到 The System Tablespace 、File-Per-Table Tablespaces、General Tablespace 三者中的任意一個(gè)地方,具體取決于你的配置和創(chuàng)建表時(shí)的 sql 語句。
2、Doublewrite Buffer
如果說 Change Buffer 是提升性能,那么 Doublewrite Buffer 就是保證數(shù)據(jù)頁的可靠性。
前面提到過,MySQL 以「頁」為讀取和寫入單位,一個(gè)「頁」里面有多行數(shù)據(jù),寫入數(shù)據(jù)時(shí),MySQL 會(huì)先寫內(nèi)存中的頁,然后再刷新到磁盤中的頁。
這時(shí)問題來了,假設(shè)在某一次從內(nèi)存刷新到磁盤的過程中,一個(gè)「頁」刷了一半,突然操作系統(tǒng)或者 MySQL 進(jìn)程奔潰了,這時(shí)候,內(nèi)存里的頁數(shù)據(jù)被清除了,而磁盤里的頁數(shù)據(jù),刷了一半,處于一個(gè)中間狀態(tài),不尷不尬,可以說是一個(gè)「不完整」,甚至是「壞掉的」的頁。
有同學(xué)說,不是有 Redo Log 么?其實(shí)這個(gè)時(shí)候 Redo Log 也已經(jīng)無力回天,Redo Log 是要在磁盤中的頁數(shù)據(jù)是正常的、沒有損壞的情況下,才能把磁盤里頁數(shù)據(jù) load 到內(nèi)存,然后應(yīng)用 Redo Log。而如果磁盤中的頁數(shù)據(jù)已經(jīng)損壞,是無法應(yīng)用 Redo Log 的。
所以,MySQL 在刷數(shù)據(jù)到磁盤之前,要先把數(shù)據(jù)寫到另外一個(gè)地方,也就是 Doublewrite Buffer,寫完后,再開始寫磁盤。Doublewrite Buffer 可以理解為是一個(gè)備份(recovery),萬一真的發(fā)生 crash,就可以利用 Doublewrite Buffer 來修復(fù)磁盤里的數(shù)據(jù)。
以上是“MySQL中InnoDB存儲(chǔ)引擎是如何設(shè)計(jì)的”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!