衆所周知,MySQL8.0之前的版本DDL是非原子的。也就是說對于複合的DDL,比如DROP TABLE t1, t2;執行過程中如果遇到server crash,有可能出現表t1被DROP掉了,但是t2沒有被DROP掉的情況。即便是一條DDL,比如CREATE TABLE t1(a int);也可能在server crash的情況下導緻建表不完整,有可能在建表失敗的情況下遺留.frm或者.ibd檔案。
上面情況出現的主要原因就是MySQL不支援原子的DDL。從圖1可以看出,MySQL8.0以前,metadata在Server layer是存儲在MyISAM引擎的系統表裡,對于事務型引擎Innodb則自己存儲一份metadata。這也導緻MySQL存在如下一些弊端:
metadata由于存儲在Server layer以及存儲引擎(這裡特指Innodb),兩份系統表很容易造成資料的不一緻。
兩份系統表存儲的資訊有所不同,通路Server layer以及存儲引擎需要使用不同API,這種設計導緻了不能很好的統一對系統metadata的通路。另外兩份API,也同時增加了代碼的維護量。
由于Server layer的metadata存儲在非事務引擎(MyISAM)裡,是以在進行crash recovery的時候就不能維持原子性。
DDL的非原子性使得Replication處理異常情況變得更加複雜。比如DROP TABLE t1, t2; 如果DROP t1成功,但是DROP t2失敗,Replication就無法保證主備一緻性了。

圖1: MySQL Data Dictionary before MySQL8.0
MySQL8.0為了解決上面的缺陷,引入了事務型DDL。首先我們看一下MySQL8.0 metadata存儲的架構變化:
圖2: MySQL Data Dictionary in MySQL8.0
圖2我們可以看到,Server layer(後面簡稱SL)以及Storage Engine(後面簡稱SE) 使用同一份data dictionary(後面簡稱DD)用來存儲metadata。SL和SE将各自需要的metadata存入DD中。由于DD使用Innodb作為存儲引擎,是以crash recovery的時候,DD可以安全的進行事務復原。
下面我們介紹一下MySQL8.0為了實作原子DDL,在源碼層面引入的一些重要資料結構:
接下來我們以CREATE TABLE為例從源碼上簡單看一下MYSQL8.0是如何實作原子DDL的。
CREATE TABLE實作的流程圖如下:
這裡我們看一下CREATE TABLE過程中新增加的幾個比較重要的函數(這裡主要看Innodb存儲引擎):
綜上篇章簡要的描述了MySQL8.0實作原子DDL的背景以及一些重點的資料結構,并對CREATE TABLE過程,以及建立過程中用到的幾個重要函數進行了分析。但是原子DDL的實作是一個非常大的工程,本篇月報由于篇幅問題,隻是挖了冰山一角。以後的月報會繼續對原子DDL的實作進行分析,希望大家持續關注。