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