一条查询SQL的执行流程
查詢SQL的執(zhí)行過程
當希望Mysql能夠高效的執(zhí)行的時候,最好的辦法就是清楚的了解Mysql是如何執(zhí)行查詢的,只有更加全面的了解SQL執(zhí)行的每一個過程,才能更好的進行SQl的優(yōu)化。
當執(zhí)行一條查詢的SQl的時候大概發(fā)生了一下的步驟:
Mysql的執(zhí)行的流程
?
?
Mysql的執(zhí)行的流程圖如下圖所示:
這里以一個實例進行說明Mysql的的執(zhí)行過程,新建一個User表,如下:
現(xiàn)在針對這個表發(fā)出一條SQl查詢:查詢每個部門中25歲以下的員工個數(shù)大于3的員工個數(shù)和部門編號,并按照人工個數(shù)降序排序和部門編號升序排序的前兩個部門。
SELECT dept,COUNT(phone) AS num FROM User WHERE age< 25 GROUP BY dept HAVING num >= 3 ORDER BY num DESC,dept ASC LIMIT 0,2; 1執(zhí)行連接器
開始執(zhí)行這條sql時,會檢查該語句是否有權限,若是沒有權限就直接返回錯誤信息,有權限會進行下一步,校驗權限的這一步是在圖一的連接器進行的,對連接用戶權限的校驗。
執(zhí)行檢索內存
相連建立之后,履行查詢語句的時候,會先行檢索內存,Mysql會先行冗余這個sql與否履行過,以此Key-Value的形式平緩適用內存中,Key是檢索預定,Value是結果集。
假如內存key遭擊中,便會間接回到給客戶端,假如沒命中,便會履行后續(xù)的操作,完工之后亦會將結果內存上去,當下一次進行查詢的時候也是如此的循環(huán)操作。
執(zhí)行分析器
分析器主要有兩步:(1)詞法分析(2)語法分析
詞法分析主要執(zhí)行提煉關鍵性字,比如select,提交檢索的表,提交字段名,提交檢索條件。語法分析主要執(zhí)行辨別你輸出的sql與否準確,是否合乎mysql的語法。
當Mysql沒有命中內存的時候,接著執(zhí)行的是 FROM student 負責把數(shù)據(jù)庫的表文件加載到內存中去,WHERE age< 60,會把所示表中的數(shù)據(jù)進行過濾,取出符合條件的記錄行,生成一張臨時表,如下圖所示。
GROUP BY dept?會把上圖的臨時表分成若干臨時表,切分的過程如下圖所示:
查詢的結果只有部門2和部門3才有符合條件的值,生成如上兩圖的臨時表。接著執(zhí)行SELECT后面的字段,SELECT后面可以是表字段也可以是聚合函數(shù)。
這里SELECT的情況與是否存在GROUP BY有關,若是不存在Mysql直接按照上圖內存中整列讀取。若是存在分別SELECT臨時表的數(shù)據(jù)。
最后生成的臨時表如下圖所示:
緊接著執(zhí)行HAVING num>2過濾員工數(shù)小于等于2的部門,對于WHERE和HAVING都是進行過濾,那么這兩者有什么不同呢?
第一點是WHERE后面只能對表字段進行過濾,不能使用聚合函數(shù),而HAVING可以過濾表字段也可以使用聚合函數(shù)進行過濾。
第二點是WHERE是對執(zhí)行from USer操作后,加載表數(shù)據(jù)到內存后,WHERE是對原生表的字段進行過濾,而HAVING是對SELECT后的字段進行過濾,也就是WHERE不能使用別名進行過濾。
因為執(zhí)行WHERE的時候,還沒有SELECT,還沒有給字段賦予別名。接著生成的臨時表如下圖所示:
最后在執(zhí)行ORDER BY后面的排序以及l(fā)imit0,2取得前兩個數(shù)據(jù),因為這里數(shù)據(jù)比較少,沒有體現(xiàn)出來。最后生成得結果也是如上圖所示。接著判斷這個sql語句是否有語法錯誤,關鍵性詞與否準確等等。
執(zhí)行優(yōu)化器
查詢優(yōu)化器會將解析樹轉化成執(zhí)行計劃。一條查詢可以有多種執(zhí)行方法,最后都是返回相同結果。優(yōu)化器的作用就是找到這其中最好的執(zhí)行計劃。
生成執(zhí)行計劃的過程會消耗較多的時間,特別是存在許多可選的執(zhí)行計劃時。如果在一條SQL語句執(zhí)行的過程中將該語句對應的最終執(zhí)行計劃進行緩存。
當相似的語句再次被輸入服務器時,就可以直接使用已緩存的執(zhí)行計劃,從而跳過SQL語句生成執(zhí)行計劃的整個過程,進而可以提高語句的執(zhí)行速度。
MySQL使用基于成本的查詢優(yōu)化器。它會嘗試預測一個查詢使用某種執(zhí)行計劃時的成本,并選擇其中成本最少的一個。
執(zhí)行執(zhí)行器
由優(yōu)化器生成得執(zhí)行計劃,交由執(zhí)行器進行執(zhí)行,執(zhí)行器調用存儲引擎得接口,存儲引擎獲取數(shù)據(jù)并返回,結束整個查詢得過程。
這里之講解了select的過程,對于update這些修改數(shù)據(jù)或者刪除數(shù)據(jù)的操作,會涉及到事務,會使用兩個日志模塊,redo log和binlog日志。具體對這兩個日志的介紹請看著一篇文章。
以前的Mysql的默認存儲引擎MyISAM引擎是沒redo log的,而現(xiàn)在的默認存儲引擎InnoDB引擎便是透過redo 復雜度來擁護事務的,保證事務能夠準確的回滾或者提交,保證事務的ACID。
1、一條查詢SQL執(zhí)行流程圖
? ? ?
2、查詢SQL執(zhí)行流程之發(fā)送SQL請求
(1)客戶端按照Mysql通信協(xié)議將SQL發(fā)送到服務端,SQL到達服務端后,服務端會單起一個線程執(zhí)行SQL。
(2)執(zhí)行時Mysql首先判斷SQL的前6個字符是否為select。并且語句中是否帶有SQL_NO_CACHE關鍵字,如果沒有則進入查詢緩存。
3、查詢SQL執(zhí)行流程之查詢緩存
查詢緩存說白了就是一個哈希表,將執(zhí)行過的語句及其結果以鍵值對的格式緩存到內存中。其中key是一個哈希值,由查詢SQL、當前要查詢的數(shù)據(jù)庫、客戶端協(xié)議版本等生成的,value就是查詢結果。如果要繞過查詢緩存,可以在SQL中加SQL_NO_CACHE字段,如:
SELECT SQL_NO_CACHE * FROM table注:Mysql8.0版本開始取消查詢緩存
4、查詢SQL執(zhí)行流程之解析器
解析器執(zhí)行流程分為兩個階段,詞法解析和語法解析
(1)首先對SQL詞法進行分析,將SQL從左到右一個字符、一個字符地輸入,然后根據(jù)構詞規(guī)則識別單詞。將會生成4個Token,如下所示:
?
(2)然后對SQL語法進行解析,判斷客戶端傳入的SQL語句是否滿足Mysql語法。此時會生成一顆語法樹,如下所示:
?
如果語法不對,將會收到如下提示
You have an error in your SQL syntax?如果解析器順利生成語法樹,就會將SQL送發(fā)到預處理器
5、查詢SQL執(zhí)行流程之預處理器
預處理器主要做兩件事情,查看SQL中列名是否正確和權限驗證
(1)首先判斷SQL語句中的列名是否存在于數(shù)據(jù)表中,再看看表名是否正確,如果不對,將返回如下錯誤提示
Unknown?column?xxx?in?‘where?clause’
(2)預處理器對SQL進行權限驗證,判斷SQL是否有操作這個表的權限,若沒有,則會返回如下錯誤信息
ERROR 1142 (42000): SELECT command denied to user 'root'@'localhost' for table 'xxx'?一切驗證通過后將語法樹傳遞給優(yōu)化器
6、查詢SQL執(zhí)行流程之優(yōu)化器
優(yōu)化器的任務就是對SQL語句進行優(yōu)化,達到最快的執(zhí)行效果,優(yōu)化器對SQL優(yōu)化完成后會將SQL變成一個執(zhí)行計劃交給執(zhí)行器
7、查詢SQL執(zhí)行流程之執(zhí)行器
執(zhí)行器就是根據(jù)執(zhí)行計劃來進行執(zhí)行查詢, 根據(jù)SQL的指令,逐條調用底層存儲引擎,逐步執(zhí)行。
總結
以上是生活随笔為你收集整理的一条查询SQL的执行流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python在IDLE中实现清屏和更改I
- 下一篇: 如何连接到sqlplus