面試被問到MySQL中一條SQL語句的執(zhí)行過程
MySQL作為最常用的關(guān)系型數(shù)據(jù)庫,無論是在應(yīng)用還是在面試中都是必須掌握的技能。

要印在腦子里面的東西
- DDL:數(shù)據(jù)定義,它用來定義數(shù)據(jù)庫對象,包括庫,表,列,通過ddl我們可以創(chuàng)建,刪除,修改數(shù)據(jù)庫和表結(jié)構(gòu);
 - DML:數(shù)據(jù)操作語言,增加刪除修改數(shù)據(jù)表中的記錄;
 - DCL:數(shù)據(jù)控制語言,定義訪問權(quán)限和安全級別;
 - DQL:數(shù)據(jù)查詢語言,用它來查詢想要的記錄。
 
SQL執(zhí)行順序:
- from;
 - join
 - on
 - where;
 - group by;
 - avg,sum.... 使用聚集函數(shù)進行計算;
 - having;
 - select;
 - distinct;
 - order by;
 - limit;
 
接下來我們就來鳥瞰msyql查詢的全貌,以下面這條sql為例。
select * from T where ID=1000;引用極客時間的這張生動的圖:

MySQL分為server層和存儲引擎層
1.Server層
server層實際上就是對sql語句進行檢查,分析,優(yōu)化,執(zhí)行,完成這些就必須擁有一些工具:連接器,查詢緩存,分析器,優(yōu)化器,執(zhí)行器。
server層還包括我們使用的所有內(nèi)置函數(shù),比如日期相關(guān)函數(shù),時間相關(guān)函數(shù),數(shù)學相關(guān)函數(shù),加密相關(guān)函數(shù)等等。
server層還包含跨存儲引擎的功能,包括存儲過程,觸發(fā)器,視圖。
總之除了存儲,其他功能都是server層干的。
(1) 連接器
連接器負責跟客戶端建立連接、獲取權(quán)限、維持和管理連接,當一個連接請求過來后,首先迎接的就是連接器,連接器除了校驗密碼外還要去獲取當前賬號所擁有的權(quán)限并保存起來,供后續(xù)流程使用,這樣一來,只要鏈接不斷開,就算你修改了密碼也不會影響到當前已經(jīng)建立的連接。
連接又分為長連接和短連接,長連接一般會一直維持,如果長時間不操作,mysql就會判斷靜止時間是否超過參數(shù)wait_timeout配置的時間,如果超過就主動斷開,這個參數(shù)默認是8小時;短連接是指每次執(zhí)行完很少的幾次查詢后就斷開,下次查詢就會再重新建立鏈接。
對于到底要使長連接還是短連接也是一個值得思考的問題,長連接可以避免頻繁創(chuàng)建連接帶來的性能消耗,因為畢竟建立連接過程還是比較復(fù)雜的,但是長連接中,隨著執(zhí)行sql的數(shù)量,可能會導致緩存增多,這些緩存只能等到連接關(guān)閉才能釋放,所以如果長連接很多,也會有內(nèi)存被占用過多的風險,從而導致OOM,進而導致進程被系統(tǒng)殺死。
那么短連接的好處和壞處就不言而喻了。
如果你用的是MySQL 5.7或更新版本,可以在每次執(zhí)行一個比較大的操作后,通過執(zhí)行mysql_reset_connection來重新初始化連接資源。這個過程不需要重連和重新做權(quán)限驗證,但是會將連接恢復(fù)到剛剛創(chuàng)建完時的狀態(tài)。
(2) 查詢緩存
mysq建立連接后,mysql會先查詢緩存,如果開啟緩存,mysql就會把查過的sql以key-value對的形式緩存起來,sql語句是key,查詢結(jié)果是value。
mysql的緩存其實并不友好,對于一個變化比較頻繁的表,前一秒查詢該表,并把結(jié)果緩存起來,后一秒對該表做了更新操作,那么緩存就會被清空,就造成辛辛苦苦保存的緩存還沒使用就被清空了,這樣給整個工作沒有帶來效率反而帶來消耗。
因此只有靜態(tài)表才適合使用緩存,靜態(tài)表一般不怎么變化,但是查詢又比較頻繁,比如配置表。
但是一般配置表本身就不會太大,不用緩存也不會看出有明顯效率問題,這也許就是MySQL 8.0版本直接將查詢緩存的整塊功能刪掉的原因吧。
(3) 分析器
如果沒有命中緩存,那就需要去執(zhí)行sql語句了,我們寫了一條查詢語句,看起來實際就是一串字符串,那mysql怎么知道這一串字符串是符合要求且能執(zhí)行的sql語句呢?分析器就是負責做這件事。
分析器先會做“詞法分析”。你輸入的是由多個字符串和空格組成的一條SQL語句,MySQL需要識別出里面的字符串分別是什么,代表什么。 MySQL從你輸入的"select"這個關(guān)鍵字識別出來,這是一個查詢語句。它也要把字符串“T”識別成“表名T”,把字符串“ID”識別成“列ID”。
做完了這些識別以后,就要做“語法分析”。根據(jù)詞法分析的結(jié)果,語法分析器會根據(jù)語法規(guī)則,判斷你輸入的這個SQL語句是否滿足MySQL語法。如果你的語句不對,就會收到“You have an error in your SQL syntax”的錯誤提醒。
一般語法錯誤會提示第一個出現(xiàn)錯誤的位置,所以你要關(guān)注的是緊接“use near”的內(nèi)容。
(4) 優(yōu)化器
解析器已經(jīng)知道這條sql語句要做什么?能不能做?接下來就是優(yōu)化器來決定怎么做,一條sql語句是可以很復(fù)雜的,各種表連接和子查詢等等,優(yōu)化器要做的就是給這條復(fù)雜的sql尋找一個優(yōu)化成查詢效率相對高的策略,比如使用哪個索引,表連接的順序等等都是在這里確認,一條sql的查詢性能和優(yōu)化器的處理是分不開的。
總之優(yōu)化器處理完,查詢方案就已經(jīng)確定了。mysql的優(yōu)化器里面涉及到很多的算法,算是比較復(fù)雜的一個模塊,后面我們在sql優(yōu)化里面單獨討論。
(5) 執(zhí)行器
MySQL通過分析器知道了你要做什么,通過優(yōu)化器知道了該怎么做,于是就進入了執(zhí)行器階段,開始執(zhí)行語句:
- 第一步就是校驗權(quán)限,看當前用戶是否對當前查詢的表具有查詢權(quán)限。
 - 第二步如果權(quán)限校驗通過,就開始調(diào)用存儲引擎的接口取出表的第一行數(shù)據(jù),然后判斷id是不是1000,如果是就存到結(jié)果集中,如果不是則跳過。
 - 第三步再調(diào)用存儲引擎引擎接口取出表的第二行數(shù)據(jù),再進行上述判斷,直到查到最后一行數(shù)據(jù)。
 
如果表中有索引,無非是在上述流程加一些索引的邏輯,后續(xù)會詳細說明,但是整體的邏輯原理是沒有變的。
2.存儲引擎層
存儲引擎顧名思義就是和存儲有關(guān),必然要和磁盤交互,msyql的存儲引擎是插件式的架構(gòu)模式,這就使得mysql的存儲引擎可以單獨實現(xiàn),也使得msyq的存儲引擎可以不止一種類型,mysql常用的存儲引擎是InnoDB、MyISAM、Memory,在MySQL 5.5.5版本InnoDB成為mysql的默認存儲引擎。當然在創(chuàng)建sql語句的時候也是可以指定使用哪一種存儲引擎的。
存儲引擎主要是提供存取功能,主要是通過自身提供的api供server層調(diào)用,從而是實現(xiàn)存取功能。
為了提高效率,不同的引擎會有不同的策略,InnoDB的索引結(jié)構(gòu)就是為了提高查詢效率的一種數(shù)據(jù)結(jié)構(gòu)。















 
 
 











 
 
 
 