前言
在預設大家學習了Mysql結構的基礎上,我們來深入的解析一下sql語句在mysql中是如何流轉和實作的.本文會分select查詢語句,和資料修改語句兩個方面講解.
下面我們先來看一下概覽圖:
接下來我們對照着概覽圖,一步步的來詳細解釋各個節點的作用.
連接配接
需要使用Mysql那麼第一步就是要連接配接Mysql.也就是我們熟悉的連接配接指令
mysql -h$ip -P$port -u$user -p
連接配接對應了Mysql的,mysql提供了連接配接的出口,設定user、password等權限校驗,使用者管理,都是在上文的connection pool中實作的.
當你連接配接成功後,可以通過show processlist檢視使用者情況.如下圖所示:
連接配接後,如果你沒有其他後續操作,連接配接指令(Commond)會設定為為Sleep,當一定時間無操作,會斷開連接配接.這個時間由wait_timeout參數控制,預設是8小時.
由于連接配接是比較耗時的操作,我們在使用的時候一般也都使用了連接配接池,使用長連接配接來避免多次擷取連接配接的消耗.
在使用長連接配接的時候,我們會發現,Mysql的記憶體會逐漸變高.這是因為MySQL 在執行過程中臨時使用的記憶體是管理在連接配接對象裡面的,在斷開連接配接的時候才會回收.那麼怎麼處理這個問題呢?
最簡單的方法當然是定期的斷開連接配接進行重連,來進行定期的清理.而Mysql 5.7以上版本,引入了mysql_reset_connection來重新初始化連接配接資源.此方法不會斷連和重連,而是把目前連接配接初始化為最開始連接配接的狀态.
緩存
在連接配接建立以後就可以執行sql語句了.
我們在設計業務的時候,在查詢緩慢的時候,最經常使用的就是緩存,在mysql内部同樣也實作了.
MySQL 拿到一個查詢請求後,會先到查詢緩存檢視之前是不是執行過這條語句.之前執行過的語句及其結果可能會以 key-value 對的形式,緩存在記憶體中.key 是查詢的語句,value 是查詢的結果.如果查到,直接傳回傳回值.如果查不到就會繼續後面的執行階段,執行完成後,執行結果會被存入查詢緩存中.
但是既然是緩存,必然也會有緩存相應的問題.比如緩存的更新問題,在資料修改,表結構變更情況下都要清理緩存.對于頻繁更新的表來說不是很實用.可以使用按需使用的方式.query_cache_type 設定成 DEMAND來關閉緩存,在需要使用的時候用SQL_CACHE顯式指定如下:
mysql> select SQL_CACHE * from T where ID=10;
notes: MySQL 8.0 版本直接将查詢緩存的整塊功能删掉了
解析器
MySQL解析器由兩部分組成
- 詞法分析
- 掃描字元流,根據構詞規則識别單個單詞.
- MySQL使用Flex來生成詞法掃描程式
- 在sql/lex.h中定義了MySQL關鍵字和函數關鍵字,用兩個數組存儲
- 文法分析
- 在詞法分析的基礎上将單詞序列組成文法短語,最後生成文法樹,送出給優化器
- 文法分析器使用Bison,在sql/sql_yacc.yy中定義了文法規則.
- 根據關系代數理論生成文法樹
在sql目錄下,有許多以sql_開頭命名的檔案,用于接受文法樹,執行不同的查詢,如sql_select.cc用于select查詢
如上所示分析器主要作用:
- 解析語句,生成文法數,提供給優化器.
- 檢查語句中的關鍵詞,表,字段是否存在. 當解析出語句有問題時會報錯You have an error in your SQL syntax如下:
mysql> elect * from t where ID=1;
ERROR 1064 (42000): 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 'elect * from t where ID=1' at line 1
優化器
經過了分析器,MySQL知道你要做什麼了.但是在開始執行之前,mysql會通過優化器優化執行.
比如在表中有多個索引的情況下,決定使用哪個索引.或者在一個語句有多表關聯(join)的時候,決定各個表的連接配接順序.
比如執行這樣的語句:
mysql> select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
既可以先從表 t1 裡面取出 c=10 的記錄的 ID 值,再根據 ID 值關聯到表 t2 ,再判斷 t2 裡面 d 的值是否等于 20.也可以先從表 t2 裡面取出 d=20 的記錄的 ID 值,再根據 ID 值關聯到 t1.再判斷 t1 裡面 c 的值是否等于 10.這兩種執行方法的邏輯結果是一樣的,但是執行的效率會有不同,而優化器的作用就是決定選擇使用哪一個方案.
執行器
在優化器覺得好方案後,就到了時間的執行了.
開始執行的時候,會再次判斷你對這個表 T 有沒有執行查詢的權限,如果沒有,就會傳回沒有權限的錯誤.如下所示:
mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'
執行器在執行的時候,會根據mysql設定的引擎,調用對應的這個引擎提供的接口在執行.
小結
本文我們用一條查詢語句的流轉過程,梳理了一下前文msyql的邏輯過程.下一節我們會根據一條修改語句來檢視修改語句下的一些不同點.