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

對于后端開發(fā)來說穴豫,數(shù)據(jù)庫是我們?nèi)粘i_發(fā)中幾乎都會使用到的渤滞。而且對于許多大型應用來說渔肩,往往數(shù)據(jù)庫就是限制其性能的瓶頸所在因俐。在以前的大多數(shù)時間里面,對數(shù)據(jù)庫的認知周偎,始終停留在一個比較淺的層面里抹剩。遂決定翻閱相關的書籍、博客和官方文檔蓉坎,讓自己對數(shù)據(jù)庫有一個全面的了解澳眷。

MySQL架構

以下是MySQL大體的組件結構


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

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


摘自MySQL實戰(zhàn)45講

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

MySQL內(nèi)置存儲引擎介紹

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

內(nèi)置存儲引擎

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

show engines

三種常見的存儲引擎區(qū)別及介紹
InnoDB

InnoDB從5.1版本以后屁药,已經(jīng)取代了MyISAM粥血,成為MySQL默認的存儲引擎了柏锄。可以從上表上看到复亏,InnoDB是唯一支持事務趾娃、XA和Savepoints的內(nèi)置存儲引擎。同時缔御,它還支持行鎖抬闷、外鍵約束等。InnoDB表基于聚簇索引建立耕突,并且采用MVCC來支持高并發(fā)笤成,同時實現(xiàn)了ANSI SQL92定義的四種隔離級別,并在引擎內(nèi)部實現(xiàn)了redo log和undo log眷茁。這些特性組合在一起炕泳,使得InnoDB成為了一個適合處理大量數(shù)據(jù)的高性能事務引擎。對于DBA來說上祈,結合server層的bin log組成的日志系統(tǒng)機制培遵,使得使用InnoDB作為數(shù)據(jù)存儲引擎的數(shù)據(jù)庫具備安全的崩潰恢復能力和快速穩(wěn)定的復制性能,這些都是其它存儲引擎所不具備的登刺。所以在Oracle收購MySQL以后籽腕,沒有了版權問題,InnoDB就毫無爭議地成為了MySQL的默認存儲引擎了纸俭。

MyISAM

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

Memory

Memory存儲引擎將表中的數(shù)據(jù)存儲到內(nèi)存中荐操,為查詢和引用其他表數(shù)據(jù)提供快速訪問。因為是存在內(nèi)存中珍策,所以數(shù)據(jù)訪問的速度一般也要快于其它存儲引擎托启,同時Memory支持Hash索引,因此在單值查找的速度非橙林妫快屯耸。同時拐迁,MySQL在執(zhí)行查詢的過程中需要使用臨時表來保存中間結果,內(nèi)部使用的臨時表就是Memory表(如果結果集大小超出Memory表的限制疗绣,則會轉換成MyISAM表)线召。

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

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

InnoDB內(nèi)存/磁盤結構及存儲邏輯結構

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存儲引擎在內(nèi)存和磁盤上的對應結構。
這里分別取兩個最常操作的update和select操作大致描述一下內(nèi)部的流轉機制(在默認的可重復讀級別下, 同時略去了所有有關加鎖釋放鎖的操作):
1.select * from xxx where id=1 語句:
(1)引擎接收到執(zhí)行計劃塔逃,會創(chuàng)建一個trx_id讯壶。
(2)查詢是否在這個內(nèi)存中,如果在患雏,則返回行鹏溯。如果在change buffer中或者不在內(nèi)存中,則從磁盤中讀入內(nèi)存(在change buffer中還要涉及merge操作更新內(nèi)存中的數(shù)據(jù))淹仑。引擎層拿到數(shù)據(jù),返回給到server層的執(zhí)行器肺孵。
(3)如果Innodb發(fā)現(xiàn)某二級索引被頻繁訪問匀借,會對該索引上創(chuàng)建一個哈希索引。下次同樣的查詢過來平窘,會直接走這個自適應哈希索引吓肋。

2.update xxx set xxx where id=1 語句:
(1)引擎接收到執(zhí)行計劃,會為該事務創(chuàng)建一個trx_id瑰艘。
(2)查詢是否在這個內(nèi)存中是鬼,如果在,則返回行紫新。如果在change buffer中或者不在內(nèi)存中均蜜,則從磁盤中讀入內(nèi)存(在change buffer中還要涉及merge操作更新內(nèi)存中的數(shù)據(jù))。引擎層拿到數(shù)據(jù)芒率,返回給到server層的執(zhí)行器囤耳。
(3)執(zhí)行器更新這行的相關列數(shù)據(jù),再通過API接口調(diào)用引擎層偶芍,更新修改后的行數(shù)據(jù)更新到內(nèi)存中充择。同時寫入redo log,此時處于prepare階段匪蟀。
(4)引擎層告知執(zhí)行器已經(jīng)已經(jīng)執(zhí)行完成椎麦,隨時可以提交事務。
(5)server層的執(zhí)行器將該操作寫入bin log
(6)執(zhí)行期通過API接口告知引擎提交事務材彪,引擎把剛剛寫入的redo log標記為commit狀態(tài)观挎,更新完成琴儿。(兩階段提交)

image.png

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

InnoDB的數(shù)據(jù)邏輯結構

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

下圖是InnoDB的數(shù)據(jù)組織形式


高性能MySQL-InnoDB聚簇索引

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

這里有一個有意思的問題怖侦,如果InnoDB的二級索引的葉子節(jié)點和MyISAM一樣篡悟,存儲的是可以直接找到實際數(shù)據(jù)的行號,那豈不是可以避免了回表的問題匾寝。我個人感覺確實是這樣的搬葬。但是那樣會存在一個問題,那就是行鎖和間隙鎖的加鎖問題艳悔。我們知道急凰,InnoDB的行鎖其實質(zhì)就是加在索引上面加的鎖,只要訪問到該索引猜年,就會在對應的索引上面加鎖(包含回表的加鎖)如果不回表的話抡锈,那么不同索引上面加鎖并且相互獨立,那么行鎖和間隙鎖就毫無意義了乔外。反過來說企孩,InnoDB為什么會做一個回表這樣的邏輯,其實是在犧牲部分二級索引定位數(shù)據(jù)頁的性能袁稽,來換取更細粒度的鎖帶來的顯著性能提升。另外擒抛,如果在二級索引上存儲的是實際數(shù)據(jù)的行號推汽,那在數(shù)據(jù)頁調(diào)整的時候,也要對這些二級索引進行更新歧沪,這同時也會導致寫性能的下降歹撒。

InnoDB的行鎖和間隙鎖

image.png

前面有提到,InnoDB的鎖是加在索引上的诊胞,行鎖的引入減少了鎖競爭的情況暖夭,從而提高了并發(fā)度。在不同隔離級別的不同語句下撵孤,加鎖情況也是不一樣的迈着。從上圖可以知道,有一些查詢甚至不需要加鎖邪码,通過基于MVCC實現(xiàn)的一致性讀就可以達到對應的隔離級別裕菠,這里又進一步提高了并發(fā)度。

總結

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

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

通過根據(jù)其作用推出它能提供的特性浪册,反過來也加深我們對各個組件的作用的理解扫腺。同時,通過思考這些組件的設計思想來實現(xiàn)對應的特性村象,這本身就是一個很有趣的過程笆环。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市厚者,隨后出現(xiàn)的幾起案子躁劣,更是在濱河造成了極大的恐慌,老刑警劉巖库菲,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件账忘,死亡現(xiàn)場離奇詭異,居然都是意外死亡熙宇,警方通過查閱死者的電腦和手機鳖擒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烫止,“玉大人蒋荚,你說我怎么就攤上這事」萑洌” “怎么了期升?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長互躬。 經(jīng)常有香客問我播赁,道長,這世上最難降的妖魔是什么吨铸? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任行拢,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘舟奠。我一直安慰自己竭缝,他們只是感情好,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布沼瘫。 她就那樣靜靜地躺著抬纸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耿戚。 梳的紋絲不亂的頭發(fā)上湿故,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音膜蛔,去河邊找鬼坛猪。 笑死,一個胖子當著我的面吹牛皂股,可吹牛的內(nèi)容都是我干的墅茉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼呜呐,長吁一口氣:“原來是場噩夢啊……” “哼就斤!你這毒婦竟也來了?” 一聲冷哼從身側響起蘑辑,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤洋机,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后洋魂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绷旗,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年副砍,在試婚紗的時候發(fā)現(xiàn)自己被綠了刁标。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡址晕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顿锰,到底是詐尸還是另有隱情谨垃,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布硼控,位于F島的核電站刘陶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏牢撼。R本人自食惡果不足惜匙隔,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望熏版。 院中可真熱鬧纷责,春花似錦捍掺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至喂柒,卻和暖如春不瓶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灾杰。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工蚊丐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艳吠。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓麦备,卻偏偏與公主長得像,于是被迫代替她去往敵國和親讲竿。 傳聞我的和親對象是個殘疾皇子泥兰,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355