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