Mysql 在命令行輸入 SELECT 語(yǔ)句后,背后發(fā)生了什么事?

前言

當(dāng)我們?cè)?Mysql 的命令行里輸入一條 SELECT 語(yǔ)句后,可能馬上就會(huì)返回我們想要的數(shù)據(jù),可能要等很久才返回?cái)?shù)據(jù),也可能執(zhí)行的過(guò)程中報(bào)了一些錯(cuò)誤。

一條簡(jiǎn)單的 SELECT 的語(yǔ)句背后到底發(fā)生了什么事,它的執(zhí)行邏輯是怎樣的?

我們來(lái)看看當(dāng)輸入一條 SELECT 語(yǔ)句后,Mysql 背后發(fā)生了一些什么事。

MySql 邏輯結(jié)構(gòu)

Mysql 分為客戶端服務(wù)端。

我們平時(shí)使用的命令行工具是客戶端,客戶端把命令發(fā)送到服務(wù)端,服務(wù)端處理完后,把結(jié)果返回給客戶端。

服務(wù)端是 Mysql 最核心的部分,所有的操作基本都在服務(wù)端完成。

MySql服務(wù)端

來(lái)自極客時(shí)間《MySQL實(shí)戰(zhàn)45講》

在服務(wù)端里又分為 Server 層存儲(chǔ)引擎層部分。

Server 層里面包含了連接器、查詢緩存、分析器、優(yōu)化器、執(zhí)行器等。

大多數(shù)的核心功能都在這一層,比如所有的內(nèi)置函數(shù),跨存儲(chǔ)引擎的功能,比如存儲(chǔ)過(guò)程 、觸發(fā)器,視圖等。

如圖,Mysql 的每一次完整操作,都是按順序的上到下執(zhí)行。

客戶端發(fā)起請(qǐng)求 -> 連接器建立連接 -> 查詢緩存或者直接到分析器進(jìn)行 SQL 語(yǔ)句分析 -> 優(yōu)化器優(yōu)化 SQL 執(zhí)行效率 -> 執(zhí)行器操存儲(chǔ)引擎讀取數(shù)據(jù)、返回?cái)?shù)據(jù)。

連接器

連接器負(fù)責(zé)客戶端跟服務(wù)端建立連接、獲取權(quán)限、維持和管理連接。

當(dāng)我們?cè)诳蛻舳藞?zhí)行mysql -u$user -p&pwd命令時(shí),就會(huì)向服務(wù)器發(fā)起一個(gè)連接請(qǐng)求。

完成TCP握手后,請(qǐng)求來(lái)到連接器這里,連接器首先會(huì)進(jìn)行身份認(rèn)證,也就是看我們輸入的用戶名、密碼是否正確。

如果不正確,則返回Access denied for user錯(cuò)誤給客戶端,結(jié)束流程。

如果認(rèn)證通過(guò),連接器會(huì)進(jìn)一步到權(quán)限表里查詢用戶所擁有的全部權(quán)限,并加載到內(nèi)存中,在該連接的生命周期內(nèi),權(quán)限的判斷都基于這里查出來(lái)的權(quán)限。

也就是說(shuō),如果在連接成功后,管理員修改了該用戶的權(quán)限是不會(huì)馬上生效的,只有該用戶重新連接,重新加載權(quán)限才會(huì)生效。

連接成功后,如果沒(méi)有后續(xù)動(dòng)作,這個(gè)連接會(huì)處于空閑狀態(tài)(Sleep),并且當(dāng)長(zhǎng)時(shí)間沒(méi)有動(dòng)作時(shí),Mysql會(huì)自動(dòng)斷開(kāi)該連接,默認(rèn)等待時(shí)長(zhǎng)是8小時(shí),可以通過(guò)修改 wait_timeout 變量來(lái)修改該時(shí)長(zhǎng)。

長(zhǎng)連接和短連接

長(zhǎng)鏈接指連接成功后,后續(xù)的請(qǐng)求會(huì)一直使用同一個(gè)連接。

短連接指在每次執(zhí)行完很少的幾次查詢后就斷開(kāi)連接,下次查詢?cè)僦匦逻B接。

因?yàn)檫B接的建立過(guò)程比較復(fù)雜,所以建議盡量使用長(zhǎng)連接。

使用長(zhǎng)連接的好處是減少頻繁連接所造成的網(wǎng)絡(luò)開(kāi)銷和系統(tǒng)開(kāi)銷,缺點(diǎn)是內(nèi)存的占用可能會(huì)不斷上漲。

因?yàn)?Mysql 在執(zhí)行過(guò)程中所使用的臨時(shí)內(nèi)存是管理在連接對(duì)象中的,只有當(dāng)連接斷開(kāi)時(shí),這些使用的資源才會(huì)被釋放掉。

如果長(zhǎng)時(shí)間得不到釋放,而長(zhǎng)連接的不斷增加,內(nèi)存占用也不斷上漲,最后可能會(huì)觸發(fā) OOM (Out Of Memory),導(dǎo)致 Mysql 被系統(tǒng)強(qiáng)行殺死。

針對(duì)這種情況,參考的解決方案有兩種:

  1. 定期斷開(kāi)長(zhǎng)連接,使用一段時(shí)間,或者判斷執(zhí)行過(guò)一個(gè)占用內(nèi)存大的查詢時(shí),斷開(kāi)連接,之后查詢?cè)僦匦逻B接。
  2. 如果用的是 5.7 或者更新的版本,可以在每次執(zhí)行完一個(gè)比較大的操作后,執(zhí)行 mysql_reset_connection 命令初始化連接資源。這個(gè)過(guò)程不需要重連和權(quán)限驗(yàn)證,只是把連接的狀態(tài)恢復(fù)到剛剛創(chuàng)建的狀態(tài)。

查詢緩存

Mysql 在每次查詢時(shí), 都會(huì)先在查詢緩存看看有沒(méi)有緩存,如果有,直接取緩存的結(jié)果返回給客戶端;如果沒(méi)有,再繼續(xù)往下執(zhí)行。

查詢緩存優(yōu)點(diǎn)是把上一次查詢的結(jié)果以 key-value 的形式緩存下來(lái),SQL 語(yǔ)句為 key, 結(jié)果集為 value。

在下次查詢時(shí)如果是相同的查詢語(yǔ)句,直接從緩存返回去,就不用繼續(xù)往下執(zhí)行復(fù)雜的邏輯,節(jié)省了時(shí)間和資源。

讀多寫(xiě)少的環(huán)境下,可以很大的提升效率。

查詢緩存有一個(gè)弊端,當(dāng)對(duì)一個(gè)表進(jìn)行更新時(shí),針對(duì)這個(gè)表的所有緩存都會(huì)失效被清空。

所以當(dāng)在一個(gè)寫(xiě)多讀少的環(huán)境下使用查詢緩存,緩存不但利用率不高,反而不斷的更新和失效會(huì)給數(shù)據(jù)庫(kù)帶來(lái)很大的壓力。

所以不建議使用查詢緩存,這個(gè)功能在 Mysql 8.0 開(kāi)始也被刪除掉了。

分析器

分析器負(fù)責(zé)對(duì) SQL 語(yǔ)句進(jìn)行詞法分析語(yǔ)法分析。

詞法分析是分析這條 SQL 語(yǔ)句是什么類型的語(yǔ)句,是查詢語(yǔ)句還是更新語(yǔ)句等,然后把 SQL 語(yǔ)句里面的表名和字段名識(shí)別出來(lái),并檢查表和字段是否存在。

語(yǔ)法分析是分析這條 SQL 語(yǔ)句的語(yǔ)法是否正確,比如 SELECT 這個(gè)關(guān)鍵字有沒(méi)有錯(cuò),是不是缺少了 FROM 關(guān)鍵字等等。

如果詞法或者語(yǔ)法不正確,就會(huì)拋出錯(cuò)誤給客戶端,并結(jié)束流程。

優(yōu)化器

SQL 語(yǔ)句經(jīng)過(guò)分析器分析無(wú)誤了,就要針對(duì) SQL 語(yǔ)句進(jìn)行優(yōu)化,比如在多個(gè)索引中,選擇哪一個(gè)索引效率會(huì)更快;JOIN 語(yǔ)句選擇哪一張去連接別一張表。

總的來(lái)說(shuō),優(yōu)化器做的事就是采取不同的選擇、不同的策略去盡可能的讓 SQL 語(yǔ)句的執(zhí)行效率更加高。

執(zhí)行器

到了執(zhí)行器,就開(kāi)始準(zhǔn)備操作存儲(chǔ)引擎,獲取數(shù)據(jù),封裝結(jié)果集。

在開(kāi)始執(zhí)行之前,執(zhí)行器首先會(huì)判斷用戶有沒(méi)有操作這張表的權(quán)限,如果沒(méi)有則返回錯(cuò)誤;有則打開(kāi)表開(kāi)始讀取數(shù)據(jù)。

執(zhí)行的流程大概如下:

  1. 調(diào)用 InnoDB 引擎接口讀取這個(gè)表的第一行,判斷這行的數(shù)據(jù)是否符合查詢條件,符合則放到結(jié)果集中,不符合則跳過(guò)。
  2. 調(diào)用引擎接口取下一行,重復(fù) 1 的判斷邏輯,直到這個(gè)表的最后一行。
  3. 執(zhí)行器把所有滿足條件的行封裝成結(jié)果集返回給客戶端。

至此,這個(gè)語(yǔ)句就執(zhí)行完成了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容