MySQL系列(1):一條SQL查詢語句是如何執(zhí)行的

平時我們在使用數(shù)據(jù)庫時往弓,看到的通常是一個整體蓄氧。比如你有一個最簡單的表,表里只有一個ID字段撇寞,在執(zhí)行下面的查詢語句時:

mysql > select * from T where ID = 1;

我們只知道輸入是一條SQL語句堂氯,輸出是MySQL返回的結(jié)果集,卻不知道這條語句在MySQL內(nèi)部的執(zhí)行過程啤握。本篇文章主要是拆解MySQL局扶,告訴你MySQL內(nèi)部都有哪些零件,分別有何作用畜埋,以此讓你加深對MySQL的理解畴蒲。

MySQL基本架構(gòu)

下圖是一張MySQL的基本架構(gòu)示意圖
MySQL基本架構(gòu)圖

大體來講模燥,MySQL由server層和存儲引擎層兩部分組成。

Server 層包括連接器么翰、查詢緩存辽旋、分析器、優(yōu)化器码耐、執(zhí)行器等溶其,涵蓋 MySQL 的大多數(shù)核心服務(wù)功能,以及所有的內(nèi)置函數(shù)(如日期束铭、時間厢绝、數(shù)學(xué)和加密函數(shù)等),所有跨存儲引擎的功能都在這一層實現(xiàn)埠褪,比如存儲過程挤庇、觸發(fā)器、視圖等渴语。

而存儲引擎層負(fù)責(zé)數(shù)據(jù)的存儲和提取昆咽。其架構(gòu)模式是插件式的牙甫,支持 InnoDB窟哺、MyISAM技肩、Memory 等多個存儲引擎。

接下來旋奢,我以開頭那條SQL語句然痊,走一遍整個執(zhí)行流程,看看每個組件的作用爽丹。

連接器

第一步辛蚊,你會先連接到這個數(shù)據(jù)庫上,這時候接待你的就是連接器初澎。連接器負(fù)責(zé)跟客戶端建立連接虑凛、獲取權(quán)限桑谍、維持和管理連接。連接命令一般是這么寫的:

mysql -h$ip -P$port -u$user -p

連接命令中的 mysql 是客戶端工具贞间,用來跟服務(wù)端建立連接雹仿。在完成經(jīng)典的 TCP 握手后,連接器就要開始認(rèn)證你的身份峻仇,這個時候用的就是你輸入的用戶名和密碼邑商。

  • 如果用戶名或密碼不對凡蚜,你就會收到一個"Access denied for user"的錯誤吭从,然后客戶端程序結(jié)束執(zhí)行影锈。
  • 如果用戶名密碼認(rèn)證通過蝉绷,連接器會到權(quán)限表里面查出你擁有的權(quán)限。之后辆床,這個連接里面的權(quán)限判斷邏輯桅狠,都將依賴于此時讀到的權(quán)限。

這就意味著咨堤,一個用戶成功建立連接后漩符,即使你用管理員賬號對這個用戶的權(quán)限做了修改嗜暴,也不會影響已經(jīng)存在連接的權(quán)限。修改完成后萎战,只有重新建立連接才會使用新的權(quán)限設(shè)置舆逃。

客戶端如果太長時間沒動靜,連接器就會自動將它斷開鸟雏。這個時間是由參數(shù) wait_timeout 控制的览祖,默認(rèn)值是 8 小時。你可以通過下面這條sql語句來查看:

mysql > show VARIABLES where variable_name='wait_timeout';

如果在連接被斷開之后又活,客戶端再次發(fā)送請求的話柳骄,就會收到一個錯誤提醒: Lost connection to MySQL server during query。這時候如果你要繼續(xù)舔清,就需要重連曲初,然后再執(zhí)行請求了。

查詢緩存

連接建立完成后抒痒,你就可以執(zhí)行 select 語句了颁褂。執(zhí)行邏輯就會來到第二步:查詢緩存。

MySQL 拿到一個查詢請求后彩届,會先到查詢緩存看看惨缆,之前是不是執(zhí)行過這條語句丰捷。之前執(zhí)行過的語句及其結(jié)果可能會以 key-value 對的形式,被直接緩存在內(nèi)存中捣染。key 是查詢的語句停巷,value 是查詢的結(jié)果畔勤。如果你的查詢能夠直接在這個緩存中找到 key,那么這個 value 就會被直接返回給客戶端庆揪。

如果語句不在查詢緩存中,就會繼續(xù)后面的執(zhí)行階段吝羞。執(zhí)行完成后钧排,執(zhí)行結(jié)果會被存入查詢緩存中。你可以看到符衔,如果查詢命中緩存糟袁,MySQL 不需要執(zhí)行后面的復(fù)雜操作,就可以直接返回結(jié)果五嫂,這個效率會很高肯尺。

但是大多數(shù)情況下则吟,建議不要使用緩存锄蹂,因為查詢緩存往往弊大于利氓仲。

MySQL為了保證查詢結(jié)果的準(zhǔn)確性,只要一個表的任何數(shù)據(jù)發(fā)生更新(包括新增得糜、修改敬扛、刪除),這個表上所有的查詢緩存都會被清空朝抖。因此對于更新數(shù)據(jù)頻繁的數(shù)據(jù)庫來說啥箭,查詢緩存的命中率會非常低。

分析器

如果沒有命中查詢緩存治宣,就要開始真正執(zhí)行語句了急侥,此時分析器開始介入。分析器的作用是侮邀,告訴MySQL你要做什么坏怪,因此它負(fù)責(zé)對 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”的錯誤提醒,比如下面這個語句 select 少打了開頭的字母“s”粪牲。

mysql> elect * from T where ID = 1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect * from T where ID = 1' at line 1

一般語法錯誤會提示第一個出現(xiàn)錯誤的位置古瓤,所以你要關(guān)注的是緊接“use near”的內(nèi)容。

加餐內(nèi)容:

補(bǔ)充一個我的疑問腺阳,關(guān)于上文提到的:

如果你的語句不對落君,就會收到“You have an error in your SQL syntax”的錯誤提醒,比如下面這個語句 select 少打了開頭的字母“s”亭引。

問題:為什么詞法分析沒發(fā)現(xiàn)elect不對绎速,而在語法分析里拋出這個錯誤?

網(wǎng)上一搜焙蚓,發(fā)現(xiàn)很多人和我有同樣的問題纹冤,遺憾的是都沒有答案。于是我查了一下MySQL的詞法分析的相關(guān)內(nèi)容购公,以下三段資料感覺比較有用:

詞法分析階段是編譯過程的第一個階段萌京,是編譯的基礎(chǔ)。這個階段的任務(wù)是從左到右一個字符一個字符地讀入源程序宏浩,即對構(gòu)成源程序的字符流進(jìn)行掃描然后根據(jù)構(gòu)詞規(guī)則識別單詞(也稱單詞符號或符號)知残。
詞法分析是編譯程序的第一個階段且是必要階段;詞法分析的核心任務(wù)是掃描绘闷、識別單詞且對識別出的單詞給出定性橡庞、定長的處理。

詞法分析器一般以函數(shù)的形式存在印蔗,供語法分析器調(diào)用扒最。

在sql/lex.h中定義了MySQL關(guān)鍵字和函數(shù)關(guān)鍵字,用兩個數(shù)組存儲华嘹。
關(guān)鍵字 static SYMBOL symbols[]
函數(shù) static SYMBOL sql_functions[]

簡單來講吧趣,就是詞法分析只負(fù)責(zé)把SQL語句中的關(guān)鍵字提取出來,但是不負(fù)責(zé)檢查語句的合法性。SQL語句合法性校驗由語法分析器完成强挫,而語法分析器會調(diào)用詞法分析器岔霸。舉個栗子,詞法分析能識別select,from,where等詞的含義俯渤,但它們之間的順序要求如何呆细,是否必須存在于SQL語句中,則由語法分析完成八匠。

優(yōu)化器

經(jīng)過了分析器絮爷,MySQL 就知道你要做什么了。在開始執(zhí)行之前梨树,還要先經(jīng)過優(yōu)化器的處理坑夯。

優(yōu)化器的作用是在表里面有多個索引的時候,決定使用哪個索引抡四;或者在一個語句有多表關(guān)聯(lián)(join)的時候柜蜈,決定各個表的連接順序。比如你有一張表T指巡,分別在c1列和c2列都建立了索引淑履,執(zhí)行下面這樣的語句:

mysql > select * from T where c1 = 0 and c2 = 0;

此時既可以使用c1列的索引,也可以使用c2列的索引厌处,這兩種執(zhí)行方法的邏輯結(jié)果是一樣的鳖谈,但是執(zhí)行的效率會有不同岁疼。優(yōu)化器的作用就是決定使用哪個索引作為最后的執(zhí)行方案阔涉。

關(guān)于優(yōu)化器是如何選擇索引的,有沒有可能選錯捷绒,本文暫不細(xì)講瑰排。

執(zhí)行器

MySQL 通過分析器知道了你要做什么,通過優(yōu)化器知道了該怎么做暖侨,于是就進(jìn)入了執(zhí)行器階段椭住,開始執(zhí)行語句。

開始執(zhí)行的時候字逗,要先判斷一下你對這個表 T 有沒有執(zhí)行查詢的權(quán)限京郑,如果沒有,就會返回沒有權(quán)限的錯誤葫掉,如下所示:

mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user 'test'@'localhost' for table 'T'

如果有權(quán)限些举,就打開表繼續(xù)執(zhí)行。打開表的時候俭厚,執(zhí)行器就會根據(jù)表的引擎定義户魏,去使用這個引擎提供的接口。

比如我們這個例子中的表 T 中,ID 字段沒有索引叼丑,那么執(zhí)行器的執(zhí)行流程是這樣的:

  1. 調(diào)用存儲引擎接口取這個表的第一行关翎,判斷 ID 值是不是 10,如果不是則跳過鸠信,如果是則將這行存在結(jié)果集中纵寝;
  2. 調(diào)用存儲引擎接口取“下一行”,重復(fù)相同的判斷邏輯星立,直到取到這個表的最后一行店雅。
  3. 執(zhí)行器將上述遍歷過程中所有滿足條件的行組成的記錄集作為結(jié)果集返回給客戶端。

至此贞铣,這個語句就執(zhí)行完成了闹啦。

小結(jié)

本文通過分析一條SQL語句的執(zhí)行過程,介紹了MySQL內(nèi)部各個組件的作用辕坝。

  • 連接器:負(fù)責(zé)和客戶端建立連接窍奋,管理連接,并驗證用戶/密碼合法性酱畅。
  • 分析器:負(fù)責(zé)對SQL語句做詞法琳袄、語法分析。
  • 優(yōu)化器:負(fù)責(zé)選擇最優(yōu)索引纺酸。
  • 執(zhí)行器:負(fù)責(zé)操作存儲引擎窖逗,并返回執(zhí)行結(jié)果。

希望你對一個 SQL 語句完整執(zhí)行流程的各個階段有一個初步的印象餐蔬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碎紊,一起剝皮案震驚了整個濱河市淫半,隨后出現(xiàn)的幾起案子缓升,更是在濱河造成了極大的恐慌,老刑警劉巖千扶,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件词爬,死亡現(xiàn)場離奇詭異秃嗜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)顿膨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門锅锨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恋沃,你說我怎么就攤上這事必搞。” “怎么了芽唇?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵顾画,是天一觀的道長取劫。 經(jīng)常有香客問我,道長研侣,這世上最難降的妖魔是什么谱邪? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮庶诡,結(jié)果婚禮上惦银,老公的妹妹穿的比我還像新娘。我一直安慰自己末誓,他們只是感情好扯俱,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喇澡,像睡著了一般迅栅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晴玖,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天读存,我揣著相機(jī)與錄音,去河邊找鬼呕屎。 笑死让簿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秀睛。 我是一名探鬼主播尔当,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蹂安!你這毒婦竟也來了椭迎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤藤抡,失蹤者是張志新(化名)和其女友劉穎侠碧,沒想到半個月后抹估,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缠黍,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年药蜻,在試婚紗的時候發(fā)現(xiàn)自己被綠了瓷式。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡语泽,死狀恐怖贸典,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情踱卵,我是刑警寧澤廊驼,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布据过,位于F島的核電站,受9級特大地震影響妒挎,放射性物質(zhì)發(fā)生泄漏绳锅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一酝掩、第九天 我趴在偏房一處隱蔽的房頂上張望鳞芙。 院中可真熱鬧,春花似錦期虾、人聲如沸原朝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喳坠。三九已至,卻和暖如春茂蚓,著一層夾襖步出監(jiān)牢的瞬間丙笋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工煌贴, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留御板,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓牛郑,卻偏偏與公主長得像怠肋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淹朋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354