mysql執行過程以及順序

前言:mysql在咱們的開發中基本天天都要面對的,做爲開發中的數據的來源,mysql承擔者存儲數據和讀寫數據的職責。由於學習和了解mysql是相當重要的,那麼當咱們在客戶端發起一個sql到出現詳細的查詢數據,這其中究竟經歷了什麼樣的過程?mysql服務端是如何處理請求的,又是如何執行sql語句的?本篇博客未來探討這個問題:mysql

本篇博客的目錄sql

一:mysql執行過程數據庫

二:mysql執行過程當中的狀態緩存

三:mysql執行的順序服務器

四:總結函數

 一:mysql執行過程性能

mysql總體的執行過程以下圖所示:學習

 

 1.1:鏈接器優化

鏈接器的主要職責就是:spa

①負責與客戶端的通訊,是半雙工模式,這就意味着某一固定時刻只能由客戶端向服務器請求或者服務器向客戶端發送數據,而不能同時進行,其中mysql在與客戶端鏈接TC/IP的

②驗證請求用戶的帳戶和密碼是否正確,若是帳戶和密碼錯誤,會報錯:Access denied for user 'root'@'localhost' (using password: YES)

③若是用戶的帳戶和密碼驗證經過,會在mysql自帶的權限表中查詢當前用戶的權限:

mysql中存在4個控制權限的表,分別爲user表,db表,tables_priv表,columns_priv表,mysql權限表的驗證過程爲:

1:User表:存放用戶帳戶信息以及全局級別(全部數據庫)權限,決定了來自哪些主機的哪些用戶能夠訪問數據庫實例
  Db表:存放數據庫級別的權限,決定了來自哪些主機的哪些用戶能夠訪問此數據庫 
 Tables_priv表:存放表級別的權限,決定了來自哪些主機的哪些用戶能夠訪問數據庫的這個表 
 Columns_priv表:存放列級別的權限,決定了來自哪些主機的哪些用戶能夠訪問數據庫表的這個字段 
  Procs_priv表:存放存儲過程和函數級別的權限

2:先從user表中的Host,User,Password這3個字段中判斷鏈接的ip、用戶名、密碼是否存在,存在則經過驗證。

3:經過身份認證後,進行權限分配,按照user,db,tables_priv,columns_priv的順序進行驗證。即先檢查全局權限表user,若是user中對應的權限爲Y,則此用戶對全部數據庫的權限都爲Y,將再也不檢查db, tables_priv,columns_priv;若是爲N,則到db表中檢查此用戶對應的具體數據庫,並獲得db中爲Y的權限;若是db中爲N,則檢查tables_priv中此數據庫對應的具體表,取得表中的權限Y,以此類推

4:若是在任何一個過程當中權限驗證不經過,都會報錯

1.2:緩存

    mysql的緩存主要的做用是爲了提高查詢的效率,緩存以key和value的哈希表形式存儲,key是具體的sql語句,value是結果的集合。若是沒法命中緩存,就繼續走到分析器的的一步,若是命中緩存就直接返回給客戶端 。不過須要注意的是在mysql的8.0版本之後,緩存被官方刪除掉了。之因此刪除掉,是由於查詢緩存的失效很是頻繁,若是在一個寫多讀少的環境中,緩存會頻繁的新增和失效。對於某些更新壓力大的數據庫來講,查詢緩存的命中率會很是低,mysql爲了維護緩存可能會出現必定的伸縮性的問題,目前在5.6的版本中已經默認關閉了,比較推薦的一種作法是將緩存放在客戶端,性能大概會提高5倍左右

1.3:分析器

   分析器的主要做用是將客戶端發過來的sql語句進行分析,這將包括預處理與解析過程,在這個階段會解析sql語句的語義,並進行關鍵詞和非關鍵詞進行提取、解析,並組成一個解析樹。具體的關鍵詞包括不限定於如下: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;

在分析器中就經過語義規則器將select from where這些關鍵詞提取和匹配出來,mysql會自動判斷關鍵詞和非關鍵詞,將用戶的匹配字段和自定義語句識別出來。這個階段也會作一些校驗:好比校驗當前數據庫是否存在user表,同時假如User表中不存在userId這個字段一樣會報錯:unknown column in field list.

1.4:優化器

可以進入到優化器階段表示sql是符合mysql的標準語義規則的而且能夠執行的,此階段主要是進行sql語句的優化,會根據執行計劃進行最優的選擇,匹配合適的索引,選擇最佳的執行方案。好比一個典型的例子是這樣的:

表T,對A、B、C列創建聯合索引,在進行查詢的時候,當sql查詢到的結果是:select xx where  B=x and A=x and C=x.不少人會覺得是用不到索引的,但其實會用到,雖然索引必須符合最左原則才能使用,可是本質上,優化器會自動將這條sql優化爲:where A=x and B=x and C=X,這種優化會爲了底層可以匹配到索引,同時在這個階段是自動按照執行計劃進行預處理,mysql會計算各個執行方法的最佳時間,最終肯定一條執行的sql交給最後的執行器

1.5:執行器

 在執行器的階段,此時會調用存儲引擎的API,API會調用存儲引擎,主要有一下存儲的引擎,不過經常使用的仍是myisam和innodb:

 

 引擎之前的名字叫作:表處理器(其實這個名字我以爲更能表達它存在的意義)負責對具體的數據文件進行操做,對sql的語義好比select或者update進行分析,執行具體的操做。在執行完之後會將具體的操做記錄到binlog中,須要注意的一點是:select不會記錄到binlog中,只有update/delete/insert纔會記錄到binlog中。而update會採用兩階段提交的方式,記錄都redolog中

二:執行的狀態

能夠經過命令:show full processlist,展現全部的處理進程,主要包含了如下的狀態,表示服務器處理客戶端的狀態,狀態包含了從客戶端發起請求到後臺服務器處理的過程,包括加鎖的過程、統計存儲引擎的信息,排序數據、搜索中間表、發送數據等。囊括了全部的mysql的全部狀態,其中具體的含義以下圖:

 三:sql的執行順序

 事實上,sql並非按照咱們的書寫順序來從前日後、左往右依次執行的,它是按照固定的順序解析的,主要的做用就是從上一個階段的執行返回結果來提供給下一階段使用,sql在執行的過程當中會有不一樣的臨時中間表,通常是按照以下順序:

例子: 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;

3.1:from

第一步就是選擇出from關鍵詞後面跟的表,這也是sql執行的第一步:表示要從數據庫中執行哪張表。

實例說明:在這個例子中就是首先從數據庫中找到表T

3.2:join on

join是表示要關聯的表,on是鏈接的條件。經過from和join on選擇出須要執行的數據庫表T和S,產生笛卡爾積,生成T和S合併的臨時中間表Temp1。on:肯定表的綁定關係,經過on產生臨時中間表Temp2.

實例說明:找到表S,生成臨時中間表Temp1,而後找到表T的id和S的id相同的部分組成成表Temp2,Temp2裏面包含着T和Sid相等的全部數據

3.3:where

where表示篩選,根據where後面的條件進行過濾,按照指定的字段的值(若是有and鏈接符會進行聯合篩選)從臨時中間表Temp2中篩選須要的數據,注意若是在此階段找不到數據,會直接返回客戶端,不會往下進行.這個過程會生成一個臨時中間表Temp3。注意在where中不可使用聚合函數,聚合函數主要是(min\max\count\sum等函數)

實例說明:在temp2臨時表集合中找到T表的name="Yrion"的數據,找到數據後會成臨時中間表Temp3,temp3裏包含name列爲"Yrion"的全部表數據

3.4:group by 

group by是進行分組,對where條件過濾後的臨時表Temp3按照固定的字段進行分組,產生臨時中間表Temp4,這個過程只是數據的順序發生改變,而數據總量不會變化,表中的數據以組的形式存在

實例說明:在temp3表數據中對mobile進行分組,查找出mobile同樣的數據,而後放到一塊兒,產生temp4臨時表。

3.5:Having

對臨時中間表Temp4進行聚合,這裏能夠爲count等計數,而後產生中間表Temp5,在此階段可使用select中的別名

實例說明:在temp4臨時表中找出條數大於2的數據,若是小於2直接被捨棄掉,而後生成臨時中間表temp5

3.6:select

對分組聚合完的表挑選出須要查詢的數據,若是爲*會解析爲全部數據,此時會產生中間表Temp6

實例說明:在此階段就是對temp5臨時聚合表中S表中的id進行篩選產生Temp6,此時temp6就只包含有s表的id列數據,而且name="Yrion",經過mobile分組數量大於2的數據

3.7:Distinct

distinct對全部的數據進行去重,此時若是有min、max函數會執行字段函數計算,而後產生臨時表Temp7

實例說明:此階段對temp5中的數據進行去重,引擎API會調用去重函數進行數據的過濾,最終只保留id第一次出現的那條數據,而後產生臨時中間表temp7

3.8:order by 

會根據Temp7進行順序排列或者逆序排列,而後插入臨時中間表Temp8,這個過程比較耗費資源

實例說明:這段會將全部temp7臨時表中的數據按照建立時間(create_time)進行排序,這個過程也不會有列或者行損失

 3.9:limit

limit對中間表Temp8進行分頁,產生臨時中間表Temp9,返回給客戶端。

實例說明:在temp7中排好序的數據,而後取前五條插入到Temp9這個臨時表中,最終返回給客戶端

ps:實際上這個過程也並非絕對這樣的,中間mysql會有部分的優化以達到最佳的優化效果,好比在select篩選出找到的數據集

 四:總結

 本篇博客總結了mysql的執行過程,以及sql的執行順序,理解這些有助於咱們對sql語句進行優化,以及明白mysql中的sql語句從寫出來到最終執行的軌跡,有助於咱們對sql有比較深刻和細緻的理解,提升咱們的數據庫理解能力。同時,對於複雜sql的執行過程、編寫都會有必定程度的意義。

相關文章
相關標籤/搜索