MySQL底層執行流程分析

寫在開頭

  MySQL 憑藉其不花錢的特性,在我們項目開發中佔有很大一部分。雖然我們會用 sql語句來進行數據查詢,但是你有了解過 MySQL 是如何進行查詢的嗎

  在面試中,我們也經常被問到SQL 優化的內容,加個索引是最簡單而且高效的一種方法。那麼你有了解過SQL爲什麼查詢速度會慢嗎

SQL爲什麼查詢速度會慢?

  一個SQL查詢的生命週期,大致可以按照順序來看:從客戶端到服務端、在服務器上進行解析、生成執行計劃 、執行、並返回結果給客戶端。其中在執行階段包含了大量的爲了檢索數據到存儲引擎的調用、以及調用後對數據的處理過程,包括排序、分組等。

  查詢速度慢的原因在於:某些不必要的額外操作。比如:某些操作被額外的重複執行很多次,某些操作執行太慢。優化查詢的目的,就是減少和消除這些操作所花費的時間。

  接下來,我們就從 MySQL 底層,來了解一下它到底是怎麼一個執行流程。

MySQL 執行流程

在這裏插入圖片描述
MySQL 執行流程,分爲 5 步:

  1. 客戶端發送一條查詢給服務器;
  2. MySQL 服務器端先檢查緩存。如果命中緩存,則直接返回結果;否則進入下一階段;
  3. MySQL 服務器端進行 SQL 解析、預處理,再由優化器生成對應的執行計劃;
  4. MySQL 根據優化器生成的執行計劃,調用存儲引擎的 API 來執行查詢;
  5. 將查詢結果返回客戶端。

下來我們就開始對 MySQL 執行的每一步進行詳細瞭解。

1.MySQL 客戶端/服務端通信

  MySQL 客戶端與服務端的通信,採用的是"半雙工"的方式。此處涉及到一個數據傳輸的概念,數據傳輸共分爲單工、半雙工、全雙工 三種。

  • 單工:數據傳輸只能在在一個方向上傳輸,一方固定爲發送端,另一方固定爲接收端;舉例:電視機
  • 半雙工:數據允許在兩個方向上傳輸。在某一時刻,只允許數據在一個方向上傳輸,即:同一時間只可以有一方接收或者發送消息,可以實現雙向通信。   
  • 全雙工:數據允許 同時 在兩個方向上傳輸。即:發送設備和接收設備都具有獨立的接收和發送能力,在同一時間可以同時接收和發送消息,實現雙向通信。距離:電話通信
    在這裏插入圖片描述

查詢 MySQL客戶端/服務端連接狀態:

  對於一個 MySQL 連接,或者說一個線程,時刻都有一個狀態來標識這個連接正在做的操作。我們可以通過命令:show full processlist / show processlist 來查看。
在這裏插入圖片描述
我們可以通過上面內容,我們可以來查看當前 MySQL 線程處於哪種狀態。Command 常用的線程命令值有以下幾種:

  1. Sleep 線程正在等待客戶端發送數據
  2. Execute 線程正在執行準備好的語句
  3. Query 連接線程正在執行查詢

Command 全部線程命令值,可參考官網介紹:https://dev.mysql.com/doc/refman/5.7/en/thread-commands.html

常見的 State 狀態 有以下幾種:

  1. Locked 線程正在等待表鎖的釋放 (MySQL 之前版本是 Locked,新版本鎖的粒度更細了)
  2. Sorting result 線程正在對結果進行排序
  3. Sending data 向請求段返回數據

日常開發中,如果某個連接被鎖住了,我們可通過kill {id}的方式將該連接殺掉。上面只介紹了常見的幾種狀態,全部狀態可參考官網介紹:(MySQL 5.7 版本)https://dev.mysql.com/doc/refman/5.7/en/general-thread-states.html

2.MySQL 查詢緩存

  數據庫連接成功,這個時候就可以執行SQL語句了。MySQL 默認是關閉緩存的,如需使用緩存,需要我們手動開啓。下文介紹默認緩存已開啓。如何開啓緩存,請繼續往下讀。

  執行語句時,MySQL 首先會去查詢緩存,查看之前有沒有執行過同樣的語句(同樣的語句指:SQL語句必須一模一樣,多一個空格,少一個空格都認爲不是一個同樣的語句)

  1. 如果緩存不存在,MySQL 會將執行的語句和結果key-value的形式存儲起來;(簡單理解爲 key=sql,value=結果集)
  2. 再次查詢時,發現緩存存在,則不會進行後續的查詢流程,直接從緩存返回。

如何打開MySQL緩存:

修改配置文件,來開啓 MySQL 緩存:

vi /etc/my.cnf,在 [mysqld] 中添加:

query_cache_size = 64M
query_cache_type = ON(兩個屬性需同時配置,緩存才能開啓生效)

然後,重啓 mysql 服務

service mysqld restart

通過命令:show variables like ‘query_cache%’;來查看是否開啓緩存(此處爲單引號,顯示錯誤是CSDN問題)
在這裏插入圖片描述
可以通過命令:show status like qcache%;來查看緩存的相關情況
在這裏插入圖片描述
緩存失效問題:

  MySQL 只要表中的數據發生變化,緩存便會失效。

  比如:我們使用語句select * from user where id = 1查詢,此時 Qcache_inserts會加 1;當再次使用該語句查詢,此時Qcache_hits命中數會加 1。

  此時,我們使用語句update user set name=xxx where id = 5修改表中數據,儘管修改的是 id = 5 的這條,和 id = 1 沒有任何關係,但是此時你再來 select * from user where id = 1查詢時, Qcache_inserts會加 1,說明緩存已經失效。

  MySQL緩存缺點: 只要修改表中數據,儘管與已緩存的數據無關聯,但是所有緩存都會失效,這是一個不好的點。

什麼情況下,數據不會被緩存:

  1. 加上SQL_NO_CACHE 參數將不緩存
  2. now()、current_date() 等函數的查詢,不會緩存(select *,now() from user; 這種是不會進入緩存的)
  3. 查詢語句不涉及表,不會緩存(select version(); ----查詢MySQL版本號 )
  4. 查詢的語句是系統表,不會緩存(select * from mysql.user;)
  5. 查詢的語句的結果,超過了 query_cache_limit 時,也不會緩存

MySQL默認關閉緩存原因?

  1. 在查詢之前,必須先檢查是否命中緩存,浪費計算資源;
  2. 如果查詢可以被緩存,name執行完成後,MySQL發現緩存中並沒有這條數據,則會將結果存入緩存,這將會帶來額外的系統消耗;
  3. 針對表的寫入更新數據時,對應表的所有緩存將都會失效;
  4. 如果查詢緩存很大或者碎片很多時,這個操作可能帶來很大的系統消耗。

MySQL緩存適用場景:

  適用於以讀爲主,數據生成之後就不常改變的業務。比如門戶類、新聞類、BI 報表類、論壇類等。

3.MySQL 查詢優化處理階段

 MySQL 的查詢優化處理,分爲以下三個階段:

  • 解析SQL
      通過 Lex 此法分析、Yacc語法分析,將 SQL 語句解析成解析樹。想了解Yacc、Lex ,請參考:Yacc 與 Lex 快速入門
  • 預處理階段
      根據 MySQL 的語法規則,進一步檢查解析樹的合法性。如:檢查數據的表和列是否存在,解析名字和別名的設置等,還會進行權限的相關驗證操作
  • 查詢優化器階段
      查詢優化器,可以將解析樹轉化爲執行計劃一條查詢可以由很多種執行方式,最後都返回相同的結果。優化器的作用就是找到這其中最好的執行計劃。
MySQL執行計劃(重點介紹)

  MySQL執行計劃

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章