MySql一條查詢語句的執(zhí)行流程究竟是怎么樣的
1.前言
一條sql語句到底在執(zhí)行時經(jīng)歷了什么?探究這個問題是學(xué)習(xí)mysql的重要步驟,面試時常被問到,也使得學(xué)習(xí)mysql時也有了知識框架的支撐,明白我們背的知識點(diǎn)到底用在哪里,筆者覺得這一點(diǎn)還是很重要的。
注:對一個知識點(diǎn)的總結(jié)不僅包含知識點(diǎn)本身,還包含對該知識點(diǎn)的聯(lián)想,這個聯(lián)想是在面試時可能被追問的,也可以自己主動說出來(我還知道。。。)加分的。
2.知識點(diǎn)
MySQL 執(zhí)行流程是怎樣的?
首先要知道的是,我們可以把mysql分成兩層,server層和數(shù)據(jù)庫引擎層,前者主要是對我們的查詢進(jìn)行處理(主要包括 {連接器},{查詢緩存}、{解析器}、{預(yù)處理器、優(yōu)化器、執(zhí)行器} 等),后者是數(shù)據(jù)真正存儲的地方(從 MySQL 5.5 版本開始, InnoDB 成為了 MySQL 的默認(rèn)存儲引擎)。
一條查詢的執(zhí)行流程如下:
第一步:通過連接器連接 MySQL 服務(wù)
mysql -h$ip -u$user -p
[連接器聯(lián)想1]: 連接經(jīng)過TCP 三次握手,斷開經(jīng)過四次揮手
[連接器聯(lián)想2]: 如果用戶密碼都沒有問題,連接器就會獲取該用戶的權(quán)限,然后保存起來,后續(xù)該用戶在此連接里的任何操作,都會基于連接開始時讀到的權(quán)限進(jìn)行權(quán)限邏輯的判斷,意思是管理員修改已登錄用戶的權(quán)限需要等他重新登錄才生效
[連接器聯(lián)想3]: 如何查看 MySQL 服務(wù)被多少個客戶端連接了?
show processlist[連接器聯(lián)想4]: 空閑連接會一直占用著嗎?MySQL 定義了空閑連接的最大空閑時長,由wait_timeout參數(shù)控制的,默認(rèn)值是 8 小時(28880秒),如果空閑連接超過了這個時間,連接器就會自動將它斷開。[連接器聯(lián)想5]: MySQL 的連接數(shù)有限制嗎?最大連接數(shù)由 max_connections 參數(shù)控制,超過這個值,系統(tǒng)就會拒絕接下來的連接請求,并報錯提示“Too many connections”。
[連接器聯(lián)想6]: 怎么解決長連接占用內(nèi)存的問題?MySQL 的連接也跟 HTTP 一樣,有短連接和長連接的概念,長連接的好處就是可以減少建立連接和斷開連接的過程,但是,使用長連接后可能會占用內(nèi)存增多,因?yàn)?MySQL 在執(zhí)行查詢過程中臨時使用內(nèi)存管理連接對象,這些連接對象資源只有在連接斷開時才會釋放。有兩種解決方式。第一種,定期斷開長連接。第二種,客戶端主動重置連接。
MySQL 5.7 版本實(shí)現(xiàn)了
mysql_reset_connection()函數(shù)的接口來重置連接,達(dá)到釋放內(nèi)存的效果。這個過程不需要重連和重新做權(quán)限驗(yàn)證,但是會將連接恢復(fù)到剛剛創(chuàng)建完時的狀態(tài)。[連接器聯(lián)想7]: 連接器的工作?與客戶端進(jìn)行 TCP 三次握手建立連接;校驗(yàn)客戶端的用戶名和密碼,如果用戶名或密碼不對,則會報錯;如果用戶名和密碼都對了,會讀取該用戶的權(quán)限,然后后面的權(quán)限邏輯判斷都基于此時讀取到的權(quán)限;
第二步:查詢緩存
連接器得工作完成后,客戶端就可以向 MySQL 服務(wù)發(fā)送 SQL 語句了,MySQL 服務(wù)收到 SQL 語句后,就會解析出 SQL 語句的第一個字段,看看是什么類型的語句。
如果 SQL 是查詢語句(select 語句),MySQL 就會先去查詢緩存( Query Cache )里查找緩存數(shù)據(jù)。
但是其實(shí)查詢緩存挺雞肋的。對于更新比較頻繁的表,查詢緩存的命中率很低的,因?yàn)橹灰粋€表有更新操作,那么這個表的查詢緩存就會被清空。
所以,MySQL 8.0 版本直接將server層查詢緩存刪掉了。
第三步:解析SQL
在正式執(zhí)行 SQL 查詢語句之前, MySQL 會先對 SQL 語句做解析,這個工作交由「解析器」來完成。
解析器會做兩件事情:詞法分析、 語法分析。
[解釋器聯(lián)想1]: 詞法分析:MySQL 會根據(jù)你輸入的字符串識別出關(guān)鍵字出來,例如,SQL語句 select username from userinfo,在分析之后,會得到4個Token,其中有2個Keyword,分別為select和from.
[解釋器聯(lián)想2]: 語法分析:根據(jù)詞法分析的結(jié)果,語法解析器會根據(jù)語法規(guī)則,判斷你輸入的這個 SQL 語句是否滿足 MySQL 語法,如果沒問題就會構(gòu)建出 SQL 語法樹,這樣方便后面模塊獲取 SQL 類型、表名、字段名、 where 條件等等。
[解釋器聯(lián)想3]: 解如果我們輸入的 SQL 語句語法不對,就會在解析器這個階段報錯。(釋器的主要作用)
[解釋器聯(lián)想4]: 解釋器只負(fù)責(zé)檢查語法和構(gòu)建語法樹,但是不會去查表或者字段存不存在。
第四步:執(zhí)行 SQL
解析SQL無誤后,執(zhí)行SQL需要經(jīng)過三個步驟:預(yù)處理器、優(yōu)化器、執(zhí)行器。
預(yù)處理器
- 檢查 SQL 查詢語句中的表或者字段是否存在;
- 將
select *中的*符號,擴(kuò)展為表上的所有列;
優(yōu)化器
優(yōu)化器主要負(fù)責(zé)將 SQL 查詢語句的執(zhí)行計劃確定下來,比如在表里面有多個索引的時候,優(yōu)化器會基于查詢成本的考慮,來決定選擇使用哪個索引。
[優(yōu)化器聯(lián)想1]: 要想知道優(yōu)化器選擇了哪個索引,我們可以在查詢語句最前面加個 explain 命令,這樣就會輸出這條 SQL 語句的執(zhí)行計劃。explain select * from product where id = 1[優(yōu)化器聯(lián)想2]: 一般來講普通索引查詢效率高于主鍵索引,當(dāng)索引覆蓋時會先考慮普通索引的B+樹上查詢,這就是執(zhí)行計劃,是優(yōu)化器決定的。
執(zhí)行器
確定了執(zhí)行計劃,接下來 MySQL 就真正開始執(zhí)行語句了,在執(zhí)行的過程中,執(zhí)行器就會和存儲引擎交互了,交互是以記錄為單位的。
- 主鍵索引查詢
select * from product where id = 1;讓InnoDB引擎通過主鍵索引B+樹搜索id=1的記錄。 - 全表掃描
select * from product where name = 'iphone';查詢條件沒有用到索引,觸發(fā)全表掃描,查詢每一條記錄判斷是否滿足條件。 - 索引下推 (MySQL 5.6 推出的查詢優(yōu)化策略)
[索引下推聯(lián)想1]: 索引下推能夠減少二級索引在查詢時的回表操作,提高查詢的效率,因?yàn)樗鼘?Server 層部分負(fù)責(zé)的事情,交給存儲引擎層去處理了。select * from t_user where age > 20 and reward = 100000;不使用索引下推(MySQL 5.6 之前的版本)時,定位到 age > 20 的一條記錄,獲取主鍵值,然后進(jìn)行回表操作,將完整的記錄返回給 Server 層,Server 層再判斷該記錄的 reward 是否等于 100000。而使用索引下推后,判斷記錄的 reward 是否等于 100000 的工作交給了存儲引擎層:定位到 age > 20 的第一條記錄,存儲引擎定位到二級索引后,先不執(zhí)行回表操作,而是先判斷一下該索引中包含的列(reward列)的條件(reward 是否等于 100000)是否成立。如果條件不成立,則直接跳過該二級索引。如果成立,則執(zhí)行回表操作,將完成記錄返回給 Server 層。
MySQL 執(zhí)行流程是怎樣的?總結(jié):
(總結(jié)只是簡單總結(jié),也就是被問到時該說的,上面的知識點(diǎn),是可能被追問時涉及的,或者自己說出來的加分項(xiàng)。)
- 連接器:建立連接,管理連接、校驗(yàn)用戶身份;
- 查詢緩存:查詢語句如果命中查詢緩存則直接返回,否則繼續(xù)往下執(zhí)行。MySQL 8.0 已刪除該模塊;
- 解析 SQL,通過解析器對 SQL 查詢語句進(jìn)行詞法分析、語法分析,然后構(gòu)建語法樹,方便后續(xù)模塊讀取表名、字段、語句類型;
- 執(zhí)行 SQL:執(zhí)行 SQL 共有三個階段:
- 預(yù)處理階段:檢查表或字段是否存在;將
select *中的*符號擴(kuò)展為表上的所有列。 - 優(yōu)化階段:基于查詢成本的考慮, 選擇查詢成本最小的執(zhí)行計劃;
- 執(zhí)行階段:根據(jù)執(zhí)行計劃執(zhí)行 SQL 查詢語句,從存儲引擎讀取記錄,返回給客戶端;
- 預(yù)處理階段:檢查表或字段是否存在;將
到此這篇關(guān)于MySql一條查詢語句的執(zhí)行流程究竟是怎么樣的文章就介紹到這了,更多相關(guān)MySql查詢語句執(zhí)行流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql存儲過程基礎(chǔ)之遍歷多表記錄后插入第三方表中詳解
這篇文章主要給大家介紹了關(guān)于mysql存儲過程教程之遍歷多表記錄后插入第三方表中的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧2018-07-07
MySQL常用命令與內(nèi)部組件及SQL優(yōu)化詳情
這篇文章主要介紹了MySQL常用命令與內(nèi)部組件及SQL優(yōu)化詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下2022-07-07
ARM64架構(gòu)下安裝mysql5.7.22的全過程
這篇文章主要介紹了ARM64架構(gòu)下安裝mysql5.7.22的全過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-07-07
利用MySQL主從配置實(shí)現(xiàn)讀寫分離減輕數(shù)據(jù)庫壓力
今天小編就為大家分享一篇關(guān)于利用MySQL主從配置實(shí)現(xiàn)讀寫分離減輕數(shù)據(jù)庫壓力,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03

