Mysql 执行流程
mysql執(zhí)行一個(gè)查詢的過程,到底做了些什么:
- 客戶端發(fā)送一條查詢給服務(wù)器;
- 服務(wù)器先檢查查詢緩存,如果命中了緩存,則立刻返回存儲(chǔ)在緩存中的結(jié)果。否則進(jìn)入下一階段。
- 服務(wù)器段進(jìn)行SQL解析、預(yù)處理,在優(yōu)化器生成對(duì)應(yīng)的執(zhí)行計(jì)劃;
- mysql根據(jù)優(yōu)化器生成的執(zhí)行計(jì)劃,調(diào)用存儲(chǔ)引擎的API來執(zhí)行查詢。
- 將結(jié)果返回給客戶端。
實(shí)際上mysql執(zhí)行的每一步都比較復(fù)雜,具體的過程如下:
1、mysql客戶端和服務(wù)器通訊
mysql客戶端和服務(wù)器之間的通訊協(xié)議是“半雙工”的,這意味著,在任何一個(gè)時(shí)刻,要么由服務(wù)器向客戶端發(fā)送數(shù)據(jù),要么由客戶端向服務(wù)器發(fā)送數(shù)據(jù),這兩個(gè)動(dòng)作不能同時(shí)發(fā)生。這種協(xié)議讓mysql通信簡單快速,但也限制了mysql。一個(gè)明顯的限制是,這意味著沒辦法進(jìn)行流量限制。一旦一端開始發(fā)生消息,另一端要接收完整個(gè)消息才能響應(yīng)他。
客戶端用一個(gè)單獨(dú)的數(shù)據(jù)包將查詢傳給服務(wù)器。一旦客戶端發(fā)送了請(qǐng)求,他能做的事情就只是等待結(jié)果了。
相反的,一般服務(wù)器響應(yīng)給用戶的數(shù)據(jù)通常很多,由多個(gè)數(shù)據(jù)包組成。當(dāng)服務(wù)器開始響應(yīng)客戶端請(qǐng)求時(shí),客戶端必須完整的接受整個(gè)返回結(jié)果,而不是簡單的只收取前面幾條結(jié)果,然后讓服務(wù)器停止發(fā)送數(shù)據(jù)。
多數(shù)連接mysql的庫函數(shù)都可以獲得全部結(jié)果并緩存到內(nèi)存里,還可以逐行獲取所需要的數(shù)據(jù)。默認(rèn)一般是獲得全部結(jié)果并緩存到內(nèi)存中。mysql通常需要等所有的數(shù)據(jù)都已經(jīng)發(fā)送給客戶端才能釋放這條查詢所占用的資源,所以接受全部結(jié)果并緩存通常可以減少服務(wù)器的壓力,讓查詢能夠早點(diǎn)結(jié)束、早點(diǎn)釋放對(duì)應(yīng)的資源。
2、查詢狀態(tài)
對(duì)于mysql連接,任何時(shí)刻都有一個(gè)狀態(tài),該狀態(tài)表示了mysql當(dāng)前正在做什么。使用show full processlist命令查看當(dāng)前狀態(tài)。在一個(gè)查詢生命周期中,狀態(tài)會(huì)變化很多次,下面是這些狀態(tài)的解釋:
- sleep:線程正在等待客戶端發(fā)送新的請(qǐng)求;
- query:線程正在執(zhí)行查詢或者正在將結(jié)果發(fā)送給客戶端;
l* ocked:在mysql服務(wù)器層,該線程正在等待表鎖。在存儲(chǔ)引擎級(jí)別實(shí)現(xiàn)的鎖,例如InnoDB的行鎖,并不會(huì)體現(xiàn)在線程狀態(tài)中。對(duì)于MyISAM來說這是一個(gè)比較典型的狀態(tài)。 - analyzing and statistics:線程正在收集存儲(chǔ)引擎的統(tǒng)計(jì)信息,并生成查詢的執(zhí)行計(jì)劃;
- copying to tmp table:線程在執(zhí)行查詢,并且將其結(jié)果集復(fù)制到一個(gè)臨時(shí)表中,這種狀態(tài)一般要么是做group by操作,要么是文件排序操作,或者union操作。如果這個(gè)狀態(tài)后面還有on disk標(biāo)記,那表示mysql正在將一個(gè)內(nèi)存臨時(shí)表放到磁盤上。
- sorting Result:線程正在對(duì)結(jié)果集進(jìn)行排序。
- sending data:線程可能在多個(gè)狀態(tài)間傳送數(shù)據(jù),或者在生成結(jié)果集,或者在想客戶端返回?cái)?shù)據(jù)。
3、查詢緩存
在解析一個(gè)查詢語句之前,如果查詢緩存是打開的,那么mysql會(huì)優(yōu)先檢查這個(gè)查詢是否命中查詢緩存中的數(shù)據(jù)。這個(gè)檢查是通過一個(gè)對(duì)大小寫敏感的哈希查找實(shí)現(xiàn)的。查詢和緩存中的查詢即使只有一個(gè)字節(jié)不同,那也不會(huì)匹配緩存結(jié)果,這種情況下查詢就會(huì)進(jìn)入下一階段的處理。
如果當(dāng)前的查詢恰好命中了查詢緩存,那么在返回查詢結(jié)果之前mysql會(huì)檢查一次用戶權(quán)限。這仍然是無須解析查詢SQL語句的,因?yàn)樵诓樵兙彺嬷幸呀?jīng)存放了當(dāng)前 查詢需要訪問的表信息。如果權(quán)限沒有問題,mysql會(huì)跳過所有其他階段,直接從緩存中拿到結(jié)果并返回給客戶端。這種情況下,查詢不會(huì)被解析,不用生成執(zhí)行計(jì)劃,不會(huì)被執(zhí)行。
4、查詢優(yōu)化處理
查詢的生命周期的下一步是將一個(gè)SQL轉(zhuǎn)換成一個(gè)執(zhí)行計(jì)劃,mysql在依照這個(gè)執(zhí)行計(jì)劃和存儲(chǔ)引擎進(jìn)行交互。這包含多個(gè)子階段:解析SQL、預(yù)處理、優(yōu)化SQL執(zhí)行計(jì)劃。這個(gè)過程中任何錯(cuò)誤都可能終止查詢。
-
語法解析器和預(yù)處理:首先mysql通過關(guān)鍵字將SQL語句進(jìn)行解析,并生成一顆對(duì)應(yīng)的“解析樹”。mysql解析器將使用mysql語法規(guī)則驗(yàn)證和解析查詢;預(yù)處理器則根據(jù)一些mysql規(guī)則進(jìn)一步檢查解析數(shù)是否合法。
-
查詢優(yōu)化器:當(dāng)語法樹被認(rèn)為是合法的了,并且由優(yōu)化器將其轉(zhuǎn)化成執(zhí)行計(jì)劃。一條查詢可以有很多種執(zhí)行方式,最后都返回相同的結(jié)果。優(yōu)化器的作用就是找到這其中最好的執(zhí)行計(jì)劃。
-
執(zhí)行計(jì)劃:mysql不會(huì)生成查詢字節(jié)碼來執(zhí)行查詢,mysql生成查詢的一棵指令樹,然后通過存儲(chǔ)引擎執(zhí)行完成這棵指令樹并返回結(jié)果。最終的執(zhí)行計(jì)劃包含了重構(gòu)查詢的全部信息。
5、查詢執(zhí)行引擎
在解析和優(yōu)化階段,mysql將生成查詢對(duì)應(yīng)的執(zhí)行計(jì)劃,mysql的查詢執(zhí)行引擎則根據(jù)這個(gè)執(zhí)行計(jì)劃來完成整個(gè)查詢。這里執(zhí)行計(jì)劃是一個(gè)數(shù)據(jù)結(jié)構(gòu),而不是和很多其他的關(guān)系型數(shù)據(jù)庫那樣對(duì)應(yīng)的字節(jié)碼。
mysql簡單的根據(jù)執(zhí)行計(jì)劃給出的指令逐步執(zhí)行。在根據(jù)執(zhí)行計(jì)劃逐步執(zhí)行的過程中,有大量的操作需要通過調(diào)用存儲(chǔ)引擎實(shí)現(xiàn)的接口來完成。為了執(zhí)行查詢,mysql只需要重復(fù)執(zhí)行計(jì)劃中的各個(gè)操作,知道完成所有的數(shù)據(jù)查詢。
6、返回結(jié)果給客戶端
查詢執(zhí)行的最后一個(gè)階段是將結(jié)果返回給客戶端。即使查詢不需要返回結(jié)果給客戶端,mysql仍然會(huì)返回這個(gè)查詢的一些信息,如該查詢影響到的行數(shù)。如果查詢可以被緩存,那么mysql在這個(gè)階段也會(huì)將結(jié)果放到查詢緩存中。
mysql將結(jié)果集返回客戶端是一個(gè)增量、逐步返回的過程。這樣有兩個(gè)好處:服務(wù)器端無須存儲(chǔ)太多的結(jié)果,也就不會(huì)因?yàn)榉祷靥嘟Y(jié)果而消耗太多的內(nèi)存;這樣處理也讓msyql客戶端第一時(shí)間獲得返回的結(jié)果。
結(jié)果集中的每一行都會(huì)以一個(gè)滿足mysql客戶端/服務(wù)器通信協(xié)議的包發(fā)送,再通過tcp協(xié)議進(jìn)行傳輸,在tcp傳輸?shù)倪^程中,可能對(duì)mysql的封包進(jìn)行緩存然后批量傳輸。
總結(jié)
以上是生活随笔為你收集整理的Mysql 执行流程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统——页面置换算法
- 下一篇: MySQL 覆盖索引、最左前缀原则、索引