MySQL 是如何執(zhí)行查詢(xún)操作的?
作為一名 Java后端程序員,MySQL應(yīng)該是接觸最多的數(shù)據(jù)庫(kù)之一,增刪改查更 MySQL數(shù)據(jù)庫(kù)的常規(guī)操作。 那么,一條 SQL語(yǔ)句在執(zhí)行的過(guò)程中經(jīng)歷了哪些流程呢?它是如何被 MySQL執(zhí)行的?這篇文章,我們將詳細(xì)地分析。
為了更好地理解,我們先來(lái)看一下 MySQL的架構(gòu)。

MySQL架構(gòu)示意圖
MySQL是典型的C/S架構(gòu),SQL整個(gè)執(zhí)行流程包括:客戶(hù)端,Server層和存儲(chǔ)引擎層三部分。


C/S架構(gòu),C是指 Client 客戶(hù)端,S是指 Server 服務(wù)端。
模塊分析
1. 客戶(hù)端
客戶(hù)端是指連接使用MySQL的終端。常見(jiàn)的MySQL客戶(hù)端有:java代碼,這個(gè)是java程序員使用最多的,比如mybatis ORM框架;navicat工具,功能強(qiáng)大,能夠可視化操作很多種數(shù)據(jù)庫(kù);mysql-cli,這個(gè)是MySQL官方自帶的客戶(hù)端;還有一些網(wǎng)頁(yè)版的客戶(hù)端。
2. Server層
Server層是MySQL的核心模塊,Server層包含 連接器、查詢(xún)緩存、分析器、優(yōu)化器、執(zhí)行器等核心組件, 涵蓋了MySQL大多數(shù)核心服務(wù)以及所有的內(nèi)置函數(shù),諸如 存儲(chǔ)過(guò)程、觸發(fā)器、視圖等所有跨存儲(chǔ)引擎的功能也都在Server層實(shí)現(xiàn)。下面將分別講解幾個(gè)核心組件。
(1) 連接器
連接器的主要功能是連接管理和權(quán)限校驗(yàn)。當(dāng)客戶(hù)端請(qǐng)求過(guò)來(lái)時(shí),首先是和Server層的連接器交互。
下面通過(guò)一個(gè)實(shí)例來(lái)講解連接層的功能,比如:mysql-cli客戶(hù)端連接MySQL Server的命令:
mysql> mysql -h 127.0.0.1 -P 3306 -uroot -p整個(gè)過(guò)程分解為:
- 輸入指令,點(diǎn)擊 Enter鍵后會(huì)完成經(jīng)典的TCP 3次握手,客戶(hù)端和MySQL Server建立TCP連接。
- 連接建立后,連接器開(kāi)始對(duì)請(qǐng)求進(jìn)行權(quán)限校驗(yàn),如果Server層配置需要密碼校驗(yàn),會(huì)提醒用戶(hù)輸入密碼,密碼正確進(jìn)入下一步,密碼錯(cuò)誤提醒"Access denied for user"; 如果Server層配置不需要密碼校驗(yàn),則直接進(jìn)入下一步
- 權(quán)限驗(yàn)證成功后,連接器會(huì)從權(quán)限表把當(dāng)前用戶(hù)的所有權(quán)限查詢(xún)并緩存起來(lái),權(quán)限緩存的生命周期一直到該連接關(guān)閉。
連接器會(huì)把權(quán)限緩存,因此,只要該連接一直存在就會(huì)使用緩存中的權(quán)限,這就意味著,即便服務(wù)器更改了該用戶(hù)的權(quán)限,只要是在權(quán)限更改前還存活的連接,新的權(quán)限不生效。這也能很好地解釋?zhuān)? 有時(shí)候服務(wù)端修改了權(quán)限配置,客戶(hù)端不能及時(shí)生效。
(2) 查詢(xún)緩存
緩存是 MySQL為了加速查詢(xún)而設(shè)置的,當(dāng)請(qǐng)求鑒權(quán)完成之后,就會(huì)到執(zhí)行緩存查詢(xún)(Server層開(kāi)啟了緩存),如果命中緩存,則直接返回,否則進(jìn)入下一步。不過(guò)根據(jù)小編劇這么多年的工作經(jīng)驗(yàn), 緩存使用的場(chǎng)景比較少,比如:MySQL中存放的是一些靜態(tài)數(shù)據(jù)或者變更頻率特別低,其他的場(chǎng)景這個(gè)功能就比較雞肋了,怎么雞肋呢?
因?yàn)橹灰獙?duì)表有更新操作,查詢(xún)緩存就會(huì)失效,如果表的更新和查詢(xún)操作比較頻繁,那么緩存就會(huì)一直處于建立和失效的頻繁交替中,最終導(dǎo)致查詢(xún)性能不但沒(méi)有提升還無(wú)形中多維護(hù)了緩存。
因此實(shí)際生產(chǎn)中,Server層都會(huì)設(shè)置 query_cache_type=DEMAND,這樣SQL默認(rèn)不會(huì)使用查詢(xún)緩存。如果有特殊需求一定要使用查詢(xún)緩存,可以顯示指定SQL_CACHE,比如下面的SQL語(yǔ)句:
mysql> select SQL_CACHE * from user where id = ?;(3) 分析器
分析器,顧名思義就是SQL語(yǔ)句進(jìn)行分析,那么,分析器對(duì)SQL會(huì)做哪些分析呢?通常來(lái)說(shuō)有:詞法分析 和 語(yǔ)法分析 兩種。
詞法分析 是判斷SQL里面的字符串進(jìn)行拆解,識(shí)別當(dāng)前SQL是什么操作,SQL里面包含多少字符串,空格等等,比如:下面的sql語(yǔ)句, 詞法分析器可以根據(jù) select來(lái)判斷當(dāng)前SQL是查詢(xún)操作,id 為需要查詢(xún)的結(jié)果,where 后面的條件等等;
mysql> select id from user where name = 'zhangsan';語(yǔ)法分析就是檢查SQL的語(yǔ)法是否正確,比如下面的SQL語(yǔ)句,把update 錯(cuò)誤的寫(xiě)成了 updater,因此語(yǔ)法分析器就能識(shí)別該SQL有語(yǔ)法錯(cuò)誤,拋出語(yǔ)法錯(cuò)誤相關(guān)的異常。
mysql> updater user set update_time = now() where id = 10;(4) 優(yōu)化器
優(yōu)化器目的是對(duì)SQL語(yǔ)句進(jìn)行優(yōu)化處理。因?yàn)镾QL語(yǔ)句的編寫(xiě)者能力不一樣,編寫(xiě)出來(lái)的SQL語(yǔ)句性能也不一樣。Server層如果完全按照SQL語(yǔ)句順序執(zhí)行,可能會(huì)造成性能問(wèn)題, 所以需要優(yōu)化,判斷語(yǔ)句能否使用索引等。比如下面的場(chǎng)景:
假如:5000萬(wàn)數(shù)據(jù)的user表中原存在一個(gè)組合索引是index_name_age(name,age),某工程師在沒(méi)有查看現(xiàn)有索引的情況下編寫(xiě)了如下的SQL語(yǔ)句:
mysql> select * from user where age = 30 and name like '張%';假如 MySQL server層完全按照SQl語(yǔ)句的順序執(zhí)行,則該SQL語(yǔ)句不會(huì)使用索引,必定會(huì)成為慢sql。而有了優(yōu)化器,語(yǔ)句就可以?xún)?yōu)化成下面的形式,完全使用上現(xiàn)有的index_name_age(name,age)索引。這下可以是不是看出了優(yōu)化器的好處。
mysql> select * from user where name like '張%' and age = 30;(5) 執(zhí)行器
執(zhí)行器就是運(yùn)行SQL語(yǔ)句。不過(guò),此處執(zhí)行器不會(huì)在Server層直接執(zhí)行SQL語(yǔ)句,而是根據(jù)數(shù)據(jù)表中執(zhí)行引擎類(lèi)型調(diào)用對(duì)應(yīng)的存儲(chǔ)引擎提的接口。至于,為什么執(zhí)行引擎不親自執(zhí)行SQL語(yǔ)句,我們會(huì)后期進(jìn)行分享。不過(guò)MySQL此處的設(shè)計(jì)符合了SOLID軟件設(shè)計(jì)原則 的依賴(lài)倒置原則。
3. 存儲(chǔ)引擎層
存儲(chǔ)引擎層負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)和提取。采用插件式的架構(gòu)模式,常見(jiàn)的存儲(chǔ)引擎有 InnoDB、MyISAM、Memory等。其中MyISAM是MySQL官方自帶的引擎, 但是因?yàn)樵撘娌恢С质聞?wù),使得能夠支持事務(wù)的InnoDB存儲(chǔ)引擎得以快速發(fā)展,并在MySQL 5.5.5版本奪嫡成功,成為了默認(rèn)存儲(chǔ)引擎。
因此,作為開(kāi)發(fā),在進(jìn)入新公司后,最好是要弄清楚公司的MySQL版本以及默認(rèn)引擎,這樣可以避免很多不必要的坑。查看指令如下:
# 查看數(shù)據(jù)庫(kù)版本
mysql> status;
# 查看默認(rèn)引擎
mysql> SHOW VARIABLES LIKE 'default_storage_engine%';總結(jié)
本文,我們?cè)敿?xì)分析了一條 SQL查詢(xún)語(yǔ)句在 MySQL中的全部執(zhí)行流程。通過(guò)了解這些流程,可以幫助我們更好的理解 MySQL的內(nèi)部結(jié)構(gòu)和原理,以及 vvvMySQL的優(yōu)化原理:
- SQL執(zhí)行會(huì)經(jīng)歷客戶(hù)端、Server層、存儲(chǔ)引擎層 3個(gè)部分。
- Server層包含 連接器、查詢(xún)緩存、分析器、優(yōu)化器、執(zhí)行器等核心組件。
- 連接器主要職責(zé)是管理連接,權(quán)限校驗(yàn)
- 查詢(xún)緩存主要職責(zé)是為查詢(xún)提供緩存
- 分析器主要職責(zé)是詞法分析和語(yǔ)法分析,目的是識(shí)別SQL是做什么,有沒(méi)有語(yǔ)法錯(cuò)誤。
- 優(yōu)化器主要職責(zé)是關(guān)注SQL的性能,優(yōu)化SQL語(yǔ)句怎么更好的去執(zhí)行,比如:匹配索引,優(yōu)化join查詢(xún)的連接順序。
- 執(zhí)行器主要職責(zé)是調(diào)用存儲(chǔ)引擎調(diào)的接口和返回結(jié)果。
- 存儲(chǔ)引擎主要職責(zé)是數(shù)據(jù)的存儲(chǔ)和提取,給執(zhí)行器提供接口。

































