一條SQL語句是如何執行的?

SQL語句執行的經過

從用戶發起請求,到服務接口調用MySQL驅動,MySQL服務器執行完SQL語句返回結果中間發生了什么?首先放一張圖來看整個過程使用到的各個組件,然后再對各個過程進行分析。

SQL語句執行鏈路

1. 連接過程

以Openresty服務器為例,Openresty是多進程+I/O多路復用結構(Nginx的I/O模型),可以支撐高的并發,一個Worker就是一個進程,一個進程可以處理多條請求。
我們知道當需要執行SQL語句時需要先于MySQL服務器建立連接,如果每個一個請求都建立一個連接,使用完再關閉連接,如果頻繁的創建和銷毀連接顯然是不合理的,浪費系統資源造成性能下降,這時連接池就出現了。

連接池

連接池會維護多個(長)連接,一個SQL語句執行時分配一個連接,使用完不會銷毀連接,而是放到空閑隊列中等待下次使用,這樣可以在高并發的場景大大減少創建、銷毀連接帶來的性能問題。

連接器

類似Web服務器通過連接池維護與數據庫服務器的連接,MySQL的連接器提供了同樣的功能,也維護了一個連接池,不同的是MySQL連接器同時還有權限驗證的功能。

  • 修改密碼不會影響已經建立的鏈接。
  • 連接完成后如果沒有操作,改連接就會處于空閑狀態,可以使用show processlist命令查看,如果長時間沒有操作連接器會在到達超時時間后斷開它。

長連接

長連接是客戶端持續有請求,使用的是同一個連接,建立連接的過程通常是比較慢的,建議盡量使用長連接。但是長連接累計較多時可能會導致內存過大(內存管理在連接對象里),比系統強行kill,引起MySQL異常重啟,可以使用以下兩種方法解決:

  • 定期斷開長連接。
  • 如果是MySQL5.7及以上的版本,可以在每次執行一個比較大的操作后執行mysql_reset_connection重新初始化連接資源(不會重新建立連接)。

2. 執行過程

查詢緩存

如果是查詢語句,而且開啟了查詢緩存,連接器拿到一個查詢請求后,會先查看查詢緩存是否有(之前執行過這條語句)。緩存key為sql語句,value是查詢結果。

  • 不建議開啟查詢緩存,除非是基本不會變的數據表。因為只要對表有更新,該表上的所有查詢緩存都會清空,導致查詢命中率很低。

分析器

分析器的功能就是對SQL語句做詞法分析和語法分析,解析這條語句要干什么,語法錯誤會返回錯誤提醒。

優化器

優化器是在表中有多個索引的時候決定使用哪個索引,或者有多表關聯(join)的時候決定各個表的連接順序。

執行器

通過分析器知道了要做什么,優化器知道了改怎么做,執行器就是真正的語句執行階段。開始執行的時候要先判斷對表是否有權限(在優化器之前也會做預檢查)。執行器會調用存儲引擎提供的接口進行讀寫操作。

3. 更新語句執行過程

查詢語句是只讀的,比較簡單,經過一系列組件最終查詢到結果返回。但是更新語句就相對復雜一些,涉及到兩個日志模塊:redo log和binlog。

redo log(重做日志)

如果每次更新都要刷盤,整個過程磁盤IO成本、查詢成本都比較高,為了提升更新效率,InnoDB引擎提供了redo log(順序寫入速度很快)。

WAL(Write-Ahead Logging):先寫日志,再寫磁盤。當有一條記錄需要更新的時候,InnoDB引擎會先將記錄寫入redo log并更新內存,這時候更新就算完成了,再需要的時候再將這個操作更新到磁盤里。

日志結構:redo log大小是固定的,比如配置一組4個文件,每個文件1G,
就可以記錄總共4G的記錄。從頭開始寫,寫完后又回到開頭循環寫入。

crash-safe:故障安全,redo log除了能提高更新操作的效率,同時還保證了故障安全,在數據庫異常時不會導致數據丟失。

binlog(歸檔日志)

MySQL最開始沒有InnoDB引擎,binlog日志只用于歸檔和復制,只依靠binlog沒有crash-safe能力。

  • redo log是InnoDB引擎獨有的,屬于存儲層;binlog是MySQL提供的,屬于server層
  • redo log是物理日志,記錄在某個數據頁上做了什么修改;binlog是邏輯日志,記錄SQL語句的原始邏輯
  • redo log是循環寫的,空間固定,用完會從頭開始寫;binlog是追加寫的,一定大小后切換到下一個文件,不會覆蓋

Buffer Pool緩沖池

InnoDB重要的內存結構,數據的操作都是在Buffer Pool中操作的,如果數據不在緩沖內存中,會先從磁盤中讀取到數據頁到緩沖池,然后再執行相關操作。

update執行過程

update T set k = k + 2 where id = '1' limit 1

  1. 執行器調引擎讀接口找id=2這一行,如果數據頁本來在內存就直接返回,否則先從磁盤load到內存中再返回。
  2. 然后執行器將k值加上2,得到新的一行數據,在調用引擎的寫接口寫入這行新數據。
  3. 引擎將這行數據更新到內存中,同時將更新操作記錄到redo log,此時redo log處于prepare狀態,然后告知執行器執行完成,可以提交事務。
  4. 執行器生成這個操作的binlog并寫入磁盤。
  5. 執行器調用存儲引擎的事務提交接口,引擎把剛寫入redo log改為commit狀態,更新完成。

兩階段提交

保證了crash-safe能力,如果不使用兩階段提交,使用binlog恢復數據庫時會導致與原數據庫狀態不一致。

假如不使用兩階段提交,在寫日志時機器發生故障:

  1. redo log寫入(比如k,本來為0,執行更新后
    k = 2)后發生故障,binlog未寫入。由于redo log寫完之后即使系統崩潰,也會能將數據恢復,恢復后這一行數據k=2。但是binlog沒寫完就crash,binlog沒有記錄這條語句,如果使用binlog來恢復時會少一個事務,恢復后的k=0,原數據庫k=2。
  2. binlog寫入后發生故障,redo log未寫入。redo log為寫入,崩潰后這個事務無效,k=0。但是binlog已經記錄了更新語句,之后恢復時會多出一個事務,恢復后k=2,原數據庫k=0。

總結

  1. MySQL連接器使用連接池維護連接,并進行檢查權限,接收一個SQL語句
  2. 然后通過分析器、優化器知道如何執行SQL語句
  3. 通過執行器與存儲引擎交互,完成數據的讀寫。
  4. 數據更新同時會寫入兩個重要的日志文件:redo log和binlog,并通過兩階段提交保證了crash-safe能力。

參考資料
【碼農有道】詳解一條 SQL 的執行過程
【極客時間】MySQL實戰45講01、02講

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

推薦閱讀更多精彩內容