MySQL系列:一句SQL,MySQL是怎么工作的?
對于MySQL而言,其實分為客戶端與服務(wù)端。
- 服務(wù)端,就是MySQL應(yīng)用,當(dāng)我們使用net start mysql命令啟動的服務(wù),其實就是啟動了MySQL的服務(wù)端。
- 客戶端,負(fù)責(zé)發(fā)送請求到服務(wù)端并從服務(wù)端獲取數(shù)據(jù),客戶端可以有多種形式,可以是我們通過mysql -uroot -p1234打開的黑窗口,也可以是我們使用的Nativecat、SQLyog等數(shù)據(jù)庫連接工具,甚至我們的程序,也可以稱作MySQL的客戶端。
而當(dāng)我們在mysql窗口或者數(shù)據(jù)庫連接工具中輸入一句sql后,我們就可以獲取到想要的數(shù)據(jù),這中間MySQL到底是怎么工作的呢?
在我們執(zhí)行SQL后,例如一句簡單的select * from user where name = ‘yanger’,客戶端發(fā)送請求到服務(wù)端,請求到達(dá)Server層,會經(jīng)過連接器、查詢緩存、分析器、優(yōu)化器、執(zhí)行器等,最終通過存儲引擎從文件系統(tǒng)獲取數(shù)據(jù)或者插入數(shù)據(jù)到文件系統(tǒng)。
連接器
在客戶端程序發(fā)起連接的時候,需要攜帶主機(jī)信息、用戶名、密碼,服務(wù)器程序會對客戶端程序提供的這些信息進(jìn)行認(rèn)證,如果認(rèn)證失敗,服務(wù)器程序會拒絕連接。
連接命令大家都比較熟悉。
mysql -h$ip -P$port -u$user -p
輸完命令之后,需要繼續(xù)輸入密碼,密碼也可以直接跟在 -p 后面,但這樣可能會導(dǎo)致你的密碼泄露,如果你連的是生產(chǎn)服務(wù)器,強(qiáng)烈建議你不要這么做。
MySQL采用TCP作為服務(wù)器和客戶端之間的網(wǎng)絡(luò)通信協(xié)議,完成 TCP 握手后,連接器主要做密碼校驗和權(quán)限獲取。
- 如果用戶名或密碼不對,你就會收到一個"Access denied for user"的錯誤
- 如果用戶名密碼認(rèn)證通過,連接器會到權(quán)限表里面查出你擁有的權(quán)限。之后,這個連接里面的權(quán)限判斷邏輯,都將依賴于此時讀到的權(quán)限
MySQL的默認(rèn)連接是8小時,由參數(shù) wait_timeout 控制的,如果超過這個時間不使用,會自動斷開,并在之后的操作中,拋出Lost connection to MySQL server during query的錯誤。
查詢緩存
針對于查詢語句,MySQL 拿到一個查詢請求后,會先到查詢緩存看看,之前是不是執(zhí)行過這條語句,之前執(zhí)行過的語句及其結(jié)果可能會以 key-value 對的形式,被直接緩存在內(nèi)存中。如果命中緩存,將直接返回結(jié)果。如果不在查詢緩存中,就會繼續(xù)后面的執(zhí)行階段。執(zhí)行完成后,執(zhí)行結(jié)果會被存入查詢緩存中。
針對于更新語句,包含插入刪除語句,MySQL 收到更新請求時,會把查詢緩存中該表相關(guān)的緩存數(shù)據(jù)全部清空。
我們可以看到,只要有更新,緩存就會失效,而對于正常的業(yè)務(wù),更新其實是比較頻繁的,也就是說,其實MySQL的查詢緩存命中率并不會很高,所以建議一般不到開啟。
可以通過設(shè)置 query_cache_type 為 DEMAND 來關(guān)閉查詢緩存功能。而事實上,在 MySQL 8.0 版本,更是直接移除了查詢緩存這一個功能。
分析器
MySQL 首先需要對SQL語句進(jìn)行分析,分析過程本質(zhì)上算是一個編譯過程,涉及詞法解析、語法分析、語義分析等階段,通過分析MySQL知道自己要做什么。
如果語句不對,就會收到“You have an error in your SQL syntax”的錯誤提醒,一般語法錯誤會提示第一個出現(xiàn)錯誤的位置,所以你要關(guān)注的是緊接“use near”的內(nèi)容。
優(yōu)化器
面對分析器拿到的結(jié)果,MySQL會做一些優(yōu)化處理,例如在表里面有多個索引的時候,決定使用哪個索引,或者在一個語句有多表關(guān)聯(lián)(join)的時候,決定各個表的連接順序。
優(yōu)化的結(jié)果就是生成一個執(zhí)行計劃,這個執(zhí)行計劃表明了應(yīng)該使用哪些索引進(jìn)行查詢,表之間的連接順序是啥樣的。我們可以使用EXPLAIN語句來查看某個語句的執(zhí)行計劃。
這里\G在命令窗口無法一行時,可以豎著展示結(jié)果,方便查看。
執(zhí)行器
經(jīng)過了分析器和優(yōu)化器,就正式進(jìn)行執(zhí)行階段了,不過執(zhí)行之前,需要做權(quán)限驗證,如果權(quán)限不足,就會拋出權(quán)限的錯誤。其實在查詢緩存的時候,一樣也會進(jìn)行權(quán)限校驗。
如果通過驗證,執(zhí)行器就打開表繼續(xù)執(zhí)行。打開表的時候,執(zhí)行器就會根據(jù)表的引擎定義,去使用這個引擎提供的接口。
存儲引擎
MySQL支持非常多種存儲引擎,常用的是InnoDB和MyISAM,MySQL的默認(rèn)存儲引擎是InnoDB。
假如我們選擇是InnoDB引擎,對于查詢,那InnoDB 會取這個表的第一行來進(jìn)行判斷是不是符合要求,符合則存在結(jié)果集中,否則繼續(xù)進(jìn)行下一行,直到該表的最后一行。
然后存儲引擎將結(jié)果返回給執(zhí)行器, 執(zhí)行器拿著結(jié)果返回給客戶端,這樣一句SQL就執(zhí)行完成了。