您好,登錄后才能下訂單哦!
這篇文章主要介紹MySQL中SQL執行流程是怎么樣的,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
先看一張架構圖,如下:
Connector
:用來支持各種語言和 SQL 的交互,比如 PHP,Python,Java 的 JDBC;
Management Serveices & Utilities
:系統管理和控制工具,包括備份恢復、MySQL 復制、集群等;
Connection Pool
:連接池,管理需要緩沖的資源,包括用戶密碼權限線程等等;
SQL Interface
:用來接收用戶的 SQL 命令,返回用戶需要的查詢結果 ;
Parser
:用來解析 SQL 語句;
Optimizer
:查詢優化器;
Cache and Buffer
:查詢緩存,除了行記錄的緩存之外,還有表緩存,Key 緩存,權限緩存等等;
Pluggable Storage Engines
:插件式存儲引擎,它提供 API 給服務層使用,跟具體的文件打交道。
把 MySQL 分成三層,跟客戶端對接的連接層,真正執行操作的服務層,和跟硬件打交道的存儲引擎層。
我們的客戶端要連接到 MySQL 服務器 3306 端口,必須要跟服務端建立連接,那么管理所有的連接,驗證客戶端的身份和權限,這些功能就在連接層完成。
連接層會把 SQL 語句交給服務層,這里面又包含一系列的流程:
比如查詢緩存的判斷、根據 SQL 調用相應的接口,對我們的 SQL 語句進行詞法和語法的解析(比如關鍵字怎么識別,別名怎么識別,語法有沒有錯誤等等)。
然后就是優化器,MySQL 底層會根據一定的規則對我們的 SQL 語句進行優化,最后再交給執行器去執行。
存儲引擎就是我們的數據真正存放的地方,在 MySQL 里面支持不同的存儲引擎。再往下就是內存或者磁盤。
以一條查詢語句為例,我們來看下 MySQL 的工作流程是什么樣的。
select name from user where id=1 and age>20;
首先咱們先來看一張圖,接下來的過程都是基于這張圖來講的:
程序或者工具要操作數據庫,第一步要跟數據庫建立連接。
在數據庫中有兩種連接:
短連接:短連接就是操作完畢以后,馬上 close 掉。
長連接:長連接可以保持打開,減少服務端創建和釋放連接的消耗,后面的程序訪問的時候還可以使用這個連接。
建立連接是比較麻煩的,首先要發送請求,發送了請求要去驗證賬號密碼,驗證完了要去看你所擁有的權限,所以在使用過程中,盡量使用長連接。
保持長連接會消耗內存。長時間不活動的連接,MySQL 服務器會斷開。可以使用sql語句查看默認時間:
show global variables like 'wait_timeout';
這個時間是由 wait_timeout 來控制的,默認都是 28800 秒,8 小時。
MySQL 內部自帶了一個緩存模塊。執行相同的查詢之后我們發現緩存沒有生效,為什么?MySQL 的緩存默認是關閉的。
show variables like 'query_cache%';
默認關閉的意思就是不推薦使用,為什么 MySQL 不推薦使用它自帶的緩存呢?
主要是因為 MySQL 自帶的緩存的應用場景有限:
第一個是它要求 SQL 語句必須一模一樣,中間多一個空格,字母大小寫不同都被認為是不同的的 SQL。
第二個是表里面任何一條數據發生變化的時候,這張表所有緩存都會失效,所以對于有大量數據更新的應用,也不適合。
所以緩存還是交給 ORM 框架(比如 MyBatis 默認開啟了一級緩存),或者獨立的緩存服務,比如 Redis 來處理更合適。
在 MySQL 8.0 中,查詢緩存已經被移除了。
為什么一條 SQL 語句能夠被識別呢?假如隨便執行一個字符串 hello,服務器報了一個 1064 的錯:
[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'hello' at line 1
這個就是 MySQL 的解析器和預處理模塊。
這一步主要做的事情是對語句基于 SQL 語法進行詞法和語法分析和語義的解析。
詞法分析就是把一個完整的 SQL 語句打碎成一個個的單詞。
比如一個簡單的 SQL 語句:select name from user where id = 1 and age >20;
它會將 select
識別出來,這是一個查詢語句,接下來會將 user
也識別出來,你是想要在這個表中做查詢,然后將 where
后面的條件也識別出來,原來我需要去查找這些內容。
語法分析會對 SQL 做一些語法檢查,比如單引號有沒有閉合,然后根據 MySQL 定義的語法規則,根據 SQL 語句生成一個數據結構。這個數據結構我們把它叫做解析樹(select_lex)。
就比如英語里面的語法 “我用 is , 你用 are ”這種,如果不對肯定是不可以的,語法分析之后發現你的 SQL 語句不符合規則,就會收到 You hava an error in your SQL syntax
的錯誤提示。
如果寫了一個詞法和語法都正確的 SQL,但是表名或者字段不存在,會在哪里報錯? 是在數據庫的執行層還是解析器?比如:select * from hello;
還是在解析的時候報錯,解析 SQL 的環節里面有個預處理器。它會檢查生成的解析樹,解決解析器無法解析的語義。比如,它會檢查表和列名是否存在,檢查名字和別名, 保證沒有歧義。預處理之后得到一個新的解析樹。
一條SQL語句是不是只有一種執行方式?或者說數據庫最終執行的SQL是不是就是我們發送的 SQL?
這個答案是否定的。一條 SQL 語句是可以有很多種執行方式的,最終返回相同的結果,他們是等價的。但是如果有這么多種執行方式,這些執行方式怎么得到的?最終選擇哪一種去執行?根據什么判斷標準去選擇?
這個就是 MySQL 的查詢優化器的模塊(Optimizer)。 查詢優化器的目的就是根據解析樹生成不同的執行計劃(Execution Plan),然后選 擇一種最優的執行計劃,MySQL 里面使用的是基于開銷(cost)的優化器,那種執行計劃開銷最小,就用哪種。
可以使用這個命令查看查詢的開銷:
show status like 'Last_query_cost';
MySQL 的優化器能處理哪些優化類型呢?
舉兩個簡單的例子:
1、當我們對多張表進行關聯查詢的時候,以哪個表的數據作為基準表。
2、有多個索引可以使用的時候,選擇哪個索引。
實際上,對于每一種數據庫來說,優化器的模塊都是必不可少的,他們通過復雜的算法實現盡可能優化查詢效率的目標。但是優化器也不是萬能的,并不是再垃圾的 SQL 語句都能自動優化,也不是每次都能選擇到最優的執行計劃,大家在編寫 SQL 語句的時候還是要注意。
優化器最終會把解析樹變成一個執行計劃(execution_plans),執行計劃是一個數據結構。當然,這個執行計劃不一定是最優的執行計劃,因為 MySQL 也有可能覆蓋不到所有的執行計劃。
我們怎么查看 MySQL 的執行計劃呢?比如多張表關聯查詢,先查詢哪張表?在執行查詢的時候可能用到哪些索引,實際上用到了什么索引?
MySQL 提供了一個執行計劃的工具。我們在 SQL 語句前面加上 EXPLAIN,就可以看到執行計劃的信息。
EXPLAIN select name from user where id=1;
在介紹存儲引擎先來問兩個問題:
1、從邏輯的角度來說,我們的數據是放在哪里的,或者說放在一個什么結構里面?
2、執行計劃在哪里執行?是誰去執行?
在關系型數據庫里面,數據是放在表 Table 里面的。我們可以把這個表理解成 Excel 電子表格的形式。所以我們的表在存儲數據的同時,還要組織數據的存儲結構,這個存儲結構就是由我們的存儲引擎決定的,所以我們也可以把存儲引擎叫做表類型。
在 MySQL 里面,支持多種存儲引擎,他們是可以替換的,所以叫做插件式的存儲引擎。為什么要支持這么多存儲引擎呢?一種還不夠用嗎?
在 MySQL 里面,每一張表都可以指定它的存儲引擎,而不是一個數據庫只能使用一個存儲引擎。存儲引擎的使用是以表為單位的。而且,創建表之后還可以修改存儲引擎。
如果對數據一致性要求比較高,需要事務支持,可以選擇 InnoDB。
如果數據查詢多更新少,對查詢性能要求比較高,可以選擇 MyISAM。
如果需要一個用于查詢的臨時表,可以選擇 Memory。
如果所有的存儲引擎都不能滿足你的需求,并且技術能力足夠,可以根據官網內部手冊用 C 語言開發一個存儲引擎。(https://dev.mysql.com/doc/internals/en/custom-engine.html%EF%BC%89 )
誰使用執行計劃去操作存儲引擎呢?這就是執行引擎(執行器),它利用存儲引擎提供的相應的 API 來完成操作。
為什么我們修改了表的存儲引擎,操作方式不需要做任何改變?因為不同功能的存儲引擎實現的 API 是相同的。
最后把數據返回給客戶端,即使沒有結果也要返回。
還是以上面的sql語句為例,再來梳理一下整個sql執行流程。
select name from user where id = 1 and age >20;
通過連接器查詢當前執行者的角色是否有權限,進行查詢。如果有的話,就繼續往下走,如果沒有的話,就會被拒絕掉,同時報出 Access denied for user
的錯誤信息;
接下來就是去查詢緩存,首先看緩存里面有沒有,如果有呢,那就沒有必要向下走,直接返回給客戶端結果就可以了;如果緩存中沒有的話,那就去執行語法解析器和預處理模塊。( MySQL 8.0 版本直接將查詢緩存的整塊功能都給刪掉了)
語法解析器和預處理主要是分析sql語句的詞法和語法是否正確,沒啥問題就會進行下一步,來到查詢優化器;
查詢優化器就會對sql語句進行一些優化,看哪種方式是最節省開銷,就會執行哪種sql語句,上面的sql有兩種優化方案:
先查詢表 user 中 id 為 1 的人的姓名,然后再從里面找年齡大于 20 歲的。
先查詢表 user 中年齡大于 20 歲的所有人,然后再從里面找 id 為 1 的。
優化器決定選擇哪個方案之后,執行引擎就去執行了。然后返回給客戶端結果。
以上是“MySQL中SQL執行流程是怎么樣的”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。