您好,登錄后才能下訂單哦!
mysql的執(zhí)行過程有哪些?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
mysql整體的執(zhí)行過程如下圖所示:
連接器的主要職責(zé)就是:
①負責(zé)與客戶端的通信,是半雙工模式,這就意味著某一固定時刻只能由客戶端向服務(wù)器請求或者服務(wù)器向客戶端發(fā)送數(shù)據(jù),而不能同時進行,其中mysql在與客戶端連接TC/IP的
②驗證請求用戶的賬戶和密碼是否正確,如果賬戶和密碼錯誤,會報錯:Access denied for user 'root'@'localhost' (using password: YES)
③如果用戶的賬戶和密碼驗證通過,會在mysql自帶的權(quán)限表中查詢當(dāng)前用戶的權(quán)限:
mysql中存在4個控制權(quán)限的表,分別為user表,db表,tables_priv表,columns_priv表,
mysql權(quán)限表的驗證過程為:
1:User表:
存放用戶賬戶信息以及全局級別(所有數(shù)據(jù)庫)權(quán)限,決定了來自哪些主機的哪些用戶可以訪問數(shù)據(jù)庫實例
Db表:存放數(shù)據(jù)庫級別
的權(quán)限,決定了來自哪些主機的哪些用戶可以訪問此數(shù)據(jù)庫
Tables_priv表:存放表級別的權(quán)限
,決定了來自哪些主機的哪些用戶可以訪問數(shù)據(jù)庫的這個表
Columns_priv表:存放列級別的權(quán)限
,決定了來自哪些主機的哪些用戶可以訪問數(shù)據(jù)庫表的這個字段
Procs_priv表:存放存儲過程和函數(shù)
級別的權(quán)限
2:先從user表中的Host,User,Password這3個字段中判斷連接的ip、用戶名、密碼是否存在,存在則通過驗證。
3:通過身份認證后,進行權(quán)限分配,按照user,db,tables_priv,columns_priv的順序進行驗證。即先檢查全局權(quán)限表user,如果user中對應(yīng)的權(quán)限為Y,則此用戶對所有數(shù)據(jù)庫的權(quán)限都為Y,將不再檢查db, tables_priv,columns_priv;如果為N,則到db表中檢查此用戶對應(yīng)的具體數(shù)據(jù)庫,并得到db中為Y的權(quán)限;如果db中為N,則檢查tables_priv中此數(shù)據(jù)庫對應(yīng)的具體表,取得表中的權(quán)限Y,以此類推
4:如果在任何一個過程中權(quán)限驗證不通過,都會報錯
mysql的緩存主要的作用是為了提升查詢的效率,緩存以key和value的哈希表形式存儲,key是具體的sql語句,value是結(jié)果的集合。如果無法命中緩存,就繼續(xù)走到分析器的的一步,如果命中緩存就直接返回給客戶端 。不過需要注意的是在mysql的8.0版本以后,緩存被官方刪除掉了。之所以刪除掉,是因為查詢緩存的失效非常頻繁,如果在一個寫多讀少的環(huán)境中,緩存會頻繁的新增和失效。對于某些更新壓力大的數(shù)據(jù)庫來說,查詢緩存的命中率會非常低,mysql為了維護緩存可能會出現(xiàn)一定的伸縮性的問題,目前在5.6的版本中已經(jīng)默認關(guān)閉了,比較推薦的一種做法是將緩存放在客戶端,性能大概會提升5倍左右
分析器的主要作用是將客戶端發(fā)過來的sql語句進行分析,這將包括預(yù)處理與解析過程,在這個階段會解析sql語句的語義,并進行關(guān)鍵詞和非關(guān)鍵詞進行提取、解析,并組成一個解析樹。具體的關(guān)鍵詞包括不限定于以下:select/update/delete/or/in/where/group by/having/count/limit等.如果分析到語法錯誤,會直接給客戶端拋出異常:ERROR:You have an error in your SQL syntax.
比如:select * from user where userId =1234;
在分析器中就通過語義規(guī)則器將select from where這些關(guān)鍵詞提取和匹配出來,mysql會自動判斷關(guān)鍵詞和非關(guān)鍵詞,將用戶的匹配字段和自定義語句識別出來。這個階段也會做一些校驗:比如校驗當(dāng)前數(shù)據(jù)庫是否存在user表,同時假如User表中不存在userId這個字段同樣會報錯:unknown column in field list.
能夠進入到優(yōu)化器階段表示sql是符合mysql的標(biāo)準(zhǔn)語義規(guī)則的并且可以執(zhí)行的,此階段主要是進行sql語句的優(yōu)化,會根據(jù)執(zhí)行計劃進行最優(yōu)的選擇,匹配合適的索引,選擇最佳的執(zhí)行方案。比如一個典型的例子是這樣的:
表T,對A、B、C列建立聯(lián)合索引,在進行查詢的時候,當(dāng)sql查詢到的結(jié)果是:select xx where B=x and A=x and C=x.很多人會以為是用不到索引的,但其實會用到,雖然索引必須符合最左原則才能使用,但是本質(zhì)上,優(yōu)化器會自動將這條sql優(yōu)化為:where A=x and B=x and C=X,這種優(yōu)化會為了底層能夠匹配到索引,同時在這個階段是自動按照執(zhí)行計劃進行預(yù)處理,mysql會計算各個執(zhí)行方法的最佳時間,最終確定一條執(zhí)行的sql交給最后的執(zhí)行器
在執(zhí)行器的階段,此時會調(diào)用存儲引擎的API,API會調(diào)用存儲引擎,主要有一下存儲的引擎,不過常用的還是myisam和innodb:
引擎以前的名字叫做:表處理器(其實這個名字我覺得更能表達它存在的意義)負責(zé)對具體的數(shù)據(jù)文件進行操作,對sql的語義比如select或者update進行分析,執(zhí)行具體的操作。在執(zhí)行完以后會將具體的操作記錄到binlog中,需要注意的一點是:select不會記錄到binlog中,只有update/delete/insert才會記錄到binlog中。而update會采用兩階段提交的方式,記錄都redolog中
可以通過命令:show full processlist,展示所有的處理進程,主要包含了以下的狀態(tài),表示服務(wù)器處理客戶端的狀態(tài),狀態(tài)包含了從客戶端發(fā)起請求到后臺服務(wù)器處理的過程,包括加鎖的過程、統(tǒng)計存儲引擎的信息,排序數(shù)據(jù)、搜索中間表、發(fā)送數(shù)據(jù)等。囊括了所有的mysql的所有狀態(tài),其中具體的含義如下圖:
事實上,sql并不是按照我們的書寫順序來從前往后、左往右依次執(zhí)行的,它是按照固定的順序解析的,主要的作用就是從上一個階段的執(zhí)行返回結(jié)果來提供給下一階段使用,sql在執(zhí)行的過程中會有不同的臨時中間表,一般是按照如下順序:
例子: select distinct s.id from T t join S s on t.id=s.id where t.name="Yrion" group by t.mobile having count(*)>2 order by s.create_time limit 5;
第一步就是選擇出from關(guān)鍵詞后面跟的表,這也是sql執(zhí)行的第一步:表示要從數(shù)據(jù)庫中執(zhí)行哪張表。
實例說明:在這個例子中就是首先從數(shù)據(jù)庫中找到表T
join是表示要關(guān)聯(lián)的表,on是連接的條件。通過from和join on選擇出需要執(zhí)行的數(shù)據(jù)庫表T和S,產(chǎn)生笛卡爾積,生成T和S合并的臨時中間表Temp1。on:確定表的綁定關(guān)系,通過on產(chǎn)生臨時中間表Temp2.
實例說明:找到表S,生成臨時中間表Temp1,然后找到表T的id和S的id相同的部分組成成表Temp2,Temp2里面包含著T和Sid相等的所有數(shù)據(jù)
where表示篩選,根據(jù)where后面的條件進行過濾,按照指定的字段的值(如果有and連接符會進行聯(lián)合篩選)從臨時中間表Temp2中篩選需要的數(shù)據(jù),注意如果在此階段找不到數(shù)據(jù),會直接返回客戶端,不會往下進行.這個過程會生成一個臨時中間表Temp3。注意在where中不可以使用聚合函數(shù),聚合函數(shù)主要是(min\max\count\sum等函數(shù))
實例說明:在temp2臨時表集合中找到T表的name="Yrion"的數(shù)據(jù),找到數(shù)據(jù)后會成臨時中間表Temp3,temp3里包含name列為"Yrion"的所有表數(shù)據(jù)
group by是進行分組,對where條件過濾后的臨時表Temp3按照固定的字段進行分組,產(chǎn)生臨時中間表Temp4,這個過程只是數(shù)據(jù)的順序發(fā)生改變,而數(shù)據(jù)總量不會變化,表中的數(shù)據(jù)以組的形式存在
實例說明:在temp3表數(shù)據(jù)中對mobile進行分組,查找出mobile一樣的數(shù)據(jù),然后放到一起,產(chǎn)生temp4臨時表。
對臨時中間表Temp4進行聚合,這里可以為count等計數(shù),然后產(chǎn)生中間表Temp5,在此階段可以使用select中的別名
實例說明:在temp4臨時表中找出條數(shù)大于2的數(shù)據(jù),如果小于2直接被舍棄掉,然后生成臨時中間表temp5
對分組聚合完的表挑選出需要查詢的數(shù)據(jù),如果為*會解析為所有數(shù)據(jù),此時會產(chǎn)生中間表Temp6
實例說明:在此階段就是對temp5臨時聚合表中S表中的id進行篩選產(chǎn)生Temp6,此時temp6就只包含有s表的id列數(shù)據(jù),并且name="Yrion",通過mobile分組數(shù)量大于2的數(shù)據(jù)
distinct對所有的數(shù)據(jù)進行去重,此時如果有min、max函數(shù)會執(zhí)行字段函數(shù)計算,然后產(chǎn)生臨時表Temp7
實例說明:此階段對temp5中的數(shù)據(jù)進行去重,引擎API會調(diào)用去重函數(shù)進行數(shù)據(jù)的過濾,最終只保留id第一次出現(xiàn)的那條數(shù)據(jù),然后產(chǎn)生臨時中間表temp7
會根據(jù)Temp7進行順序排列或者逆序排列,然后插入臨時中間表Temp8,這個過程比較耗費資源
實例說明:這段會將所有temp7臨時表中的數(shù)據(jù)按照創(chuàng)建時間(create_time)進行排序,這個過程也不會有列或者行損失
limit對中間表Temp8進行分頁,產(chǎn)生臨時中間表Temp9,返回給客戶端。
實例說明:在temp7中排好序的數(shù)據(jù),然后取前五條插入到Temp9這個臨時表中,最終返回給客戶端
ps:實際上這個過程也并不是絕對這樣的,中間mysql會有部分的優(yōu)化以達到最佳的優(yōu)化效果,比如在select篩選出找到的數(shù)據(jù)集
看完上述內(nèi)容,你們掌握mysql的執(zhí)行過程有哪些的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。