mysql 查询执行过程_深入浅出Mysql(一)——sql查询执行过程
一、sql查詢執(zhí)行過程概括
下面給出的mysql基本架構(gòu)示意圖,從中你可以清楚的mysql的各個(gè)模塊和執(zhí)行過程。
大體來說可以分為兩部分Server層和儲(chǔ)存引擎層。Server層包括連接器、查詢緩存、分析器、優(yōu)化器、執(zhí)行器等,覆蓋了mysql的大部分核心服務(wù)功能,以及所有的內(nèi)置函數(shù)(如日期、時(shí)間、數(shù)字和加密函數(shù)等)
儲(chǔ)存引擎層負(fù)責(zé)數(shù)據(jù)的儲(chǔ)存和提取。其架構(gòu)模式是插件式的,支持Innodb、MyISAM等多個(gè)儲(chǔ)存引擎?,F(xiàn)在最常用的儲(chǔ)存引擎是Innodb,從Mysql5.5.5開始為其默認(rèn)引擎。
從圖中不難看出所有的引擎都是公用server層。不知道每個(gè)組件干什么用?先對(duì)圖中的組件有一個(gè)大概印象,接下來將介紹server層的一些組件的作用。
二、連接器
我們會(huì)先要連接到數(shù)據(jù)庫,這時(shí)候接待你的就是連接器,連接器負(fù)責(zé)客戶端和數(shù)據(jù)庫建立連接、獲取權(quán)限、維持和管理連接??蛻舳诉B接的命令一般會(huì)這樣寫:
mysql -h$ip -u$name -p$pwd
在完成經(jīng)典的tcp三次握手之后建立連接、一旦建立連接和認(rèn)證通過,連接器會(huì)從權(quán)限表中查詢你擁有的權(quán)限,此連接的權(quán)限都會(huì)依賴此權(quán)限(修改權(quán)限后也不會(huì)改變,除非重新啟動(dòng))
連接完成后,如果沒有動(dòng)作,則會(huì)處于空閑狀態(tài),可以用show processlist, 下面是命令的返回結(jié)果,其中Sleep表示有一個(gè)空閑連接
當(dāng)客戶端太長時(shí)間沒有動(dòng)靜,連接器就會(huì)自動(dòng)斷開。這個(gè)時(shí)間參數(shù)可以根據(jù)wait_timeout控制,默認(rèn)是8小時(shí)。
在數(shù)據(jù)庫里面,長連接是指連接成功之后,客戶端有請(qǐng)求,則會(huì)一直用這個(gè)連接。短鏈接是指每一次執(zhí)行很少的查詢后就會(huì)斷開連接,之后查詢則需要重新建立連接。
建立連接的過程比較復(fù)雜,占用的時(shí)間也比較長 ,所以筆者建議最好使用長連接。
但是長連接也不是十全十美,當(dāng)你建立長連接之后,你可能會(huì)發(fā)現(xiàn)mysql占用的內(nèi)存漲的非常快,因?yàn)閙ysql在執(zhí)行的過程中所產(chǎn)生的臨時(shí)對(duì)象是管理在該連接對(duì)象里面的。這些資源在連接斷開的時(shí)候才會(huì)釋放,當(dāng)長連接持續(xù)過久,可能內(nèi)存占用過大,就會(huì)被系統(tǒng)強(qiáng)行殺掉,從表面上看是mysql異常重啟了。
所以我們一般會(huì)怎么解決這種問題呢。我們一般會(huì)考慮下面兩種方案:定期斷開長連接。在使用一段時(shí)間后或者執(zhí)行一次占內(nèi)存較大的查詢后會(huì)斷開連接,之后查詢?cè)龠B接。
如果是mysql5.7后的版本,可以通過執(zhí)行mysql_reset_connection來初始化資源,該過程不會(huì)去重新連接和驗(yàn)證權(quán)限
三、查詢緩存
當(dāng)建立連接完成后,就可以執(zhí)行查詢語句了,此時(shí)會(huì)執(zhí)行查詢邏輯的第二步:查詢緩存
可以參考上圖,mysql拿到一個(gè)查詢后,會(huì)先到查詢緩存去看看之前是否執(zhí)行過此條語句。之前執(zhí)行的結(jié)果會(huì)以key-value的形式被直接存在內(nèi)存里面。如果語句不在緩存中,則會(huì)繼續(xù)執(zhí)行下面的步驟,最后將結(jié)果緩存到查詢緩存中。
但是一般情況下都不會(huì)建議用查詢緩存,因?yàn)橐坏?duì)一張表進(jìn)行更新插入等更改表的操作,關(guān)于這個(gè)表的緩存就是被清空。由此導(dǎo)致查詢緩存的命中率就會(huì)很低。所以除非你有一張靜態(tài)表,很長時(shí)間才會(huì)更新一次,否則建議不用查詢緩存。
mysql中可以把query_cache_type設(shè)置成DEMAND,此時(shí)默認(rèn)的sql就不會(huì)執(zhí)行緩存,需要緩存時(shí)需要顯示指定:
select SQL_CACHE * from T where ID=10
值得注意的是,再mysql8.0版本中查詢緩存的功能被完全刪掉了。
四、分析器
如果沒有命中緩存,就開始真正的執(zhí)行語句了。首先,mysql需要知道你要做什么,所以需要對(duì)sql進(jìn)行解析。
分析器首先會(huì)對(duì)sql進(jìn)行詞法分析,mysql需要識(shí)別sql語句的字符串分別是什么,代表什么。詞法分析會(huì)把例如“select”這些關(guān)鍵字識(shí)別出來,也會(huì)把字符串“T”識(shí)別成表名“T”。
做完詞法分析后,就要做語法分析。語法分析會(huì)根據(jù)語法規(guī)則判斷輸入的sql語句是否滿足mysql語法。比如你的“select”少了一個(gè)s,收到“You have an error in your SQL syntax"的錯(cuò)誤提醒。關(guān)于分析器的詞法分析和語法分析具體過程和實(shí)現(xiàn)原理可以單獨(dú)寫一篇文章,在之后的文章中會(huì)給出。
五、優(yōu)化器
在分析器之后,mysql就知道你要做什么了。開始執(zhí)行之前,還需要優(yōu)化器處理。
優(yōu)化器的主要作用是在表中有多個(gè)索引的時(shí)候,決定用哪個(gè)索引;或者在一個(gè)語句有多表關(guān)聯(lián)(join)的時(shí)候,決定各表的連接順序。以下面的sql語句為例子:
select * from t1 join t2 on ID where t1.c=10 and t2.d=20;
既可以從t1中取出c等于10的記錄,然后再關(guān)聯(lián)到t2,然后再判斷t2表中d是否等于20的行;也可以從t2中取出d等于20的記錄,然后再關(guān)聯(lián)到t1,然后再判斷t1表中的c是否等于10 。優(yōu)化器會(huì)更具上兩種哪個(gè)的執(zhí)行效率更高而決定用哪種方案。
對(duì)于優(yōu)化器一些具體的實(shí)現(xiàn)方案,比如怎么選擇索引等,后面會(huì)再文章中解釋。
六、執(zhí)行器
優(yōu)化器完成以后,就要到執(zhí)行器的階段了。執(zhí)行器開始執(zhí)行的時(shí)候會(huì)判斷你對(duì)這個(gè)表是否有查詢權(quán)限(如果在之前的查詢緩存返回結(jié)果,會(huì)在返回結(jié)果之前也做一次權(quán)限驗(yàn)證)。下面是沒有權(quán)限認(rèn)證的一個(gè)示例:
mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'
當(dāng)驗(yàn)證權(quán)限之后,就會(huì)打開表繼續(xù)執(zhí)行,執(zhí)行器會(huì)根據(jù)表的引擎定義,去使用這個(gè)引擎提供的接口。
還是以上面例子分析,假如ID字段中沒有索引,則執(zhí)行的流程是這樣的:調(diào)用InnoDB引擎接口取這個(gè)表的第一行,判斷ID值是否為10,如果不是則跳過,如果是則將 這行存在結(jié)果集中。
調(diào)用引擎接口,取下一行,判斷相同的邏輯,直到取到最后一行。
執(zhí)行器將上面所有的結(jié)果集返回客戶端。
對(duì)于有索引的的表,執(zhí)行邏輯也差不多。第一次就會(huì)執(zhí)行”滿足條件的第一行“接口,之后循環(huán)取“滿足條件的下一行”這個(gè)接口。
在慢查詢?nèi)罩局?#xff0c;你會(huì)看見一個(gè)rows_examined的字段,該字段會(huì)表示語句執(zhí)行過程中掃描了多少行。這個(gè)值是在執(zhí)行器在掃描每一行的時(shí)候累加的。在有些場景下,執(zhí)行器調(diào)用一次,在引擎內(nèi)部則掃描了多行,因此引擎掃描行數(shù)rows_examined 并不是完全相同的。之后準(zhǔn)備寫一篇文章來講存儲(chǔ)引擎的內(nèi)部機(jī)制,里面會(huì)有詳細(xì)的說明。
七、總結(jié)
這篇文章介紹了mysql的邏輯架構(gòu),希望可以幫助大家對(duì)mysql的完整執(zhí)行流程的各個(gè)階段有一個(gè)初步的印象。對(duì)于每個(gè)階段細(xì)節(jié)問題,將會(huì)在之后的篇幅中展開。
總結(jié)
以上是生活随笔為你收集整理的mysql 查询执行过程_深入浅出Mysql(一)——sql查询执行过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度确认其类 ChatGPT 产品名为“
- 下一篇: 逆天!小米二合一笔记本12.4开售 25