Mysql引擎介紹及InnoDB邏輯存儲結構

對于后端開發來說,數據庫是我們日常開發中幾乎都會使用到的。而且對于許多大型應用來說,往往數據庫就是限制其性能的瓶頸所在。在以前的大多數時間里面,對數據庫的認知,始終停留在一個比較淺的層面里。遂決定翻閱相關的書籍、博客和官方文檔,讓自己對數據庫有一個全面的了解。

MySQL架構

以下是MySQL大體的組件結構


摘自https://www.rathishkumar.in/2016/04/understanding-mysql-architecture.html

如果只關心和聚焦于客戶端向MySQL發送一條sql語句大致主要會涉及到的Server層的組件,可以查看下圖:


摘自MySQL實戰45講

上面這張圖的箭頭標識和注釋也說得比較清楚了。如果想要更加詳細的說明,可以自行查閱相關文獻資料。需要說明的是在MySQL8.0中,已經將查詢緩存整個去掉了。

MySQL內置存儲引擎介紹

上圖介紹的MySQL架構大致可以分成Server層和存儲引擎層的。MySQL提供的基于插件式的存儲引擎,使得我們可以根據不同的需要選擇不同的引擎,甚至是在同一個schema中的不同表,也可以使用不同的存儲引擎。而實際的數據,也是存儲在存儲引擎中的。不同的存儲引擎的架構和對數據的組織方式也有所不同。正是這些不同,決定了這些存儲引擎提供了不同的特性和功能。

內置存儲引擎

我們可以使用show engines來查看當前mysql內置了哪些存儲引擎

show engines

三種常見的存儲引擎區別及介紹
InnoDB

InnoDB從5.1版本以后,已經取代了MyISAM,成為MySQL默認的存儲引擎了。可以從上表上看到,InnoDB是唯一支持事務、XA和Savepoints的內置存儲引擎。同時,它還支持行鎖、外鍵約束等。InnoDB表基于聚簇索引建立,并且采用MVCC來支持高并發,同時實現了ANSI SQL92定義的四種隔離級別,并在引擎內部實現了redo log和undo log。這些特性組合在一起,使得InnoDB成為了一個適合處理大量數據的高性能事務引擎。對于DBA來說,結合server層的bin log組成的日志系統機制,使得使用InnoDB作為數據存儲引擎的數據庫具備安全的崩潰恢復能力和快速穩定的復制性能,這些都是其它存儲引擎所不具備的。所以在Oracle收購MySQL以后,沒有了版權問題,InnoDB就毫無爭議地成為了MySQL的默認存儲引擎了。

MyISAM

在MySQL5.1及之前的版本,MyISAM都是默認的存儲引擎。雖然不支持事務、不支持行級鎖,崩潰后無法安全恢復。但是還MyISAM還是提供了許多其它的特性,包括全文索引、壓縮、空間函數(GIS)等。這些特性在某些場景下的性能是高于其它存儲引擎的,比如需要存儲和批量查詢歸檔日志數據,MyISAM引擎能提供較高的處理效率。

Memory

Memory存儲引擎將表中的數據存儲到內存中,為查詢和引用其他表數據提供快速訪問。因為是存在內存中,所以數據訪問的速度一般也要快于其它存儲引擎,同時Memory支持Hash索引,因此在單值查找的速度非常快。同時,MySQL在執行查詢的過程中需要使用臨時表來保存中間結果,內部使用的臨時表就是Memory表(如果結果集大小超出Memory表的限制,則會轉換成MyISAM表)。

使用哪一種引擎需要靈活選擇,一個數據庫中多個表可以使用不同引擎以滿足各種性能和實際需求,使用合適的存儲引擎,將會提高整個數據庫的性能

功 能 MYISAM Memory InnoDB
存儲限制 256TB RAM 64TB
支持哈希索引 No Yes No
支持全文索引 Yes No No
支持數索引 Yes Yes Yes
支持數據緩存 No N/A Yes
支持外鍵 No No Yes

InnoDB內存/磁盤結構及存儲邏輯結構

InnoDB總體架構
https://dev.mysql.com/doc/refman/5.5/en/innodb-architecture.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-architecture.html

上面這張圖是InnoDB存儲引擎在內存和磁盤上的對應結構。
這里分別取兩個最常操作的update和select操作大致描述一下內部的流轉機制(在默認的可重復讀級別下, 同時略去了所有有關加鎖釋放鎖的操作):
1.select * from xxx where id=1 語句:
(1)引擎接收到執行計劃,會創建一個trx_id。
(2)查詢是否在這個內存中,如果在,則返回行。如果在change buffer中或者不在內存中,則從磁盤中讀入內存(在change buffer中還要涉及merge操作更新內存中的數據)。引擎層拿到數據,返回給到server層的執行器。
(3)如果Innodb發現某二級索引被頻繁訪問,會對該索引上創建一個哈希索引。下次同樣的查詢過來,會直接走這個自適應哈希索引。

2.update xxx set xxx where id=1 語句:
(1)引擎接收到執行計劃,會為該事務創建一個trx_id。
(2)查詢是否在這個內存中,如果在,則返回行。如果在change buffer中或者不在內存中,則從磁盤中讀入內存(在change buffer中還要涉及merge操作更新內存中的數據)。引擎層拿到數據,返回給到server層的執行器。
(3)執行器更新這行的相關列數據,再通過API接口調用引擎層,更新修改后的行數據更新到內存中。同時寫入redo log,此時處于prepare階段。
(4)引擎層告知執行器已經已經執行完成,隨時可以提交事務。
(5)server層的執行器將該操作寫入bin log
(6)執行期通過API接口告知引擎提交事務,引擎把剛剛寫入的redo log標記為commit狀態,更新完成。(兩階段提交)

image.png

上面就是5.5版本下的文件組織,可以看到,每個schema都有一個文件夾,文件夾里面有 db.opt和*.frm格式的文件。db.opt存放的是字符集和字符集排序規則信息(字符文件,可以打開),frm文件存的是表結構等信息,官方同時也給出說明,frm里的信息和InnoDB數據字典有所重疊,是出于歷史遺留原因(參見)。另外如果你沒有設置innodb_file_per_tale=ON那么所有的數據文件都將存儲在ibdata1文件中。所以這個文件會隨著數據的增長而增長。同時我們也可以看到,InnoDB結構圖中5.7相對與5.5最大的變化,就是對于ibdata1的拆分,它把原本共享表空間,undo表空間和臨時表空間從ibdata1中分了出來。好處當然就是結構更加清晰,更加方便獨立管理,不會出現之前臨時表空間不再使用釋放了,ibdata1文件還是那么大等情況。

InnoDB的數據邏輯結構

從上面InnoDB的架構圖里面的右半部分可以知道,無論是索引還是數據,InnoDB都把它們存在.idb后綴(或者ibdata1)的文件中。而在MyISAM中,索引和數據是分別存儲在MYI和MYD文件中的。

下圖是InnoDB的數據組織形式


高性能MySQL-InnoDB聚簇索引

從圖中可以看出,InnoDB數據其實就是保存在聚簇索引的葉子節點中的,并且按照主鍵列順序存儲在數據文件中的。
相比之下,MyISAM的數據則是按照插入的順序存儲在磁盤上的,其索引的葉子節點存儲的是可以定位到實際數據的行號(或者是可以找到其物理位置的地址,這里隱藏了頁的物理細節)。
這兩種數據組織形式,使得下面兩種引擎有如下區別:
1.由于使用聚簇索引,所以無法同時把數據行存放在兩個地方,所以一個表只能有一個聚簇索引。而InnoDB的二級索引的葉子節點也只能存儲聚簇索引上的主鍵值,從而導致二級索引(除覆蓋索引以外)在查詢數據的時候需要回表。
2.也由于MyISAM的索引不存在聚簇索引,葉子節點存儲的是實際數據的行號,所以對MyISAM而言,主鍵索引和其它索引一樣,不存在定位實際數據塊上的性能差異。

這里有一個有意思的問題,如果InnoDB的二級索引的葉子節點和MyISAM一樣,存儲的是可以直接找到實際數據的行號,那豈不是可以避免了回表的問題。我個人感覺確實是這樣的。但是那樣會存在一個問題,那就是行鎖和間隙鎖的加鎖問題。我們知道,InnoDB的行鎖其實質就是加在索引上面加的鎖,只要訪問到該索引,就會在對應的索引上面加鎖(包含回表的加鎖)如果不回表的話,那么不同索引上面加鎖并且相互獨立,那么行鎖和間隙鎖就毫無意義了。反過來說,InnoDB為什么會做一個回表這樣的邏輯,其實是在犧牲部分二級索引定位數據頁的性能,來換取更細粒度的鎖帶來的顯著性能提升。另外,如果在二級索引上存儲的是實際數據的行號,那在數據頁調整的時候,也要對這些二級索引進行更新,這同時也會導致寫性能的下降。

InnoDB的行鎖和間隙鎖

image.png

前面有提到,InnoDB的鎖是加在索引上的,行鎖的引入減少了鎖競爭的情況,從而提高了并發度。在不同隔離級別的不同語句下,加鎖情況也是不一樣的。從上圖可以知道,有一些查詢甚至不需要加鎖,通過基于MVCC實現的一致性讀就可以達到對應的隔離級別,這里又進一步提高了并發度。

總結

其實當我們大概了解了InnoDB架構組件中各個組件的作用,以及其數據存儲的邏輯結構。也就大概明白了為什么InnoDB提供了這么多其它存儲引擎不能提供的相關特性。例如:

1.redo log及對應的兩階段提交協議的引入,使得引擎可以提供在系統崩潰的時候提供安全崩潰恢復機制。
2.undo log機制的引入,每一事務都有一個單調遞增的trx_id,使得Innodb可以基于MVCC對相關的事務做一致性讀(或者稱為快照讀)。
3.InnoDB基于聚簇索引的數據組織形式,多數情況下通過行鎖,間隙鎖和快照讀實現了四種隔離級別。這種方式相比與直接加表鎖,性能更高,更加適合高并發場景。

通過根據其作用推出它能提供的特性,反過來也加深我們對各個組件的作用的理解。同時,通過思考這些組件的設計思想來實現對應的特性,這本身就是一個很有趣的過程。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373