MySQL基礎架構
SELECT * FROM student WHERE stu_id = 007;
這樣一條簡單的 SQL 語句,可以從 student 表中查詢得到 stu_id 爲 007 的數據,學會寫 SQL 語句後,在使用數據庫時,只能觀察到數據庫執行了 SQL 語句,並且返回了所需要的數據。那麼,MySQL 在拿到 SQL 語句之後做了哪些操作呢?
這涉及到 MySQL 的基礎架構設計,分爲 Service 層和存儲引擎層,Service 層負責處理與客戶端通信、SQL語句的解析和所有內置函數等,而存儲引擎層則提供數據的存儲和讀寫接口,其中 Service 層又包含了連接器,緩存,優化器,分析器和執行器。存儲引擎層,包含了不同的存儲引擎,MySQL 默認是 InnoDB,此外還有 MyISAM 引擎。詳見下圖:
- 連接器:負責接待客戶端,驗證權限
- 緩存:查詢時,若命中緩存則直接返回結果
- 分析器:分析 SQl 語句的語法和詞法
- 優化器:確定 SQL 語句的最佳執行方案
- 執行器:根據優化器的方案,操作存儲引擎拿到結果並返回
連接器
連接器的工作,就是負責處理所有客戶端的連接請求,在完成TCP握手後,驗證賬號密碼,並且得到對應的權限信息,用於這個連接後續對數據庫操作時的權限判斷。
可以通過show processlist
查看當前的連接數:
mysql> show processlist;
+----+------+-----------------+-------+---------+-------+----------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------------+-------+---------+-------+----------+------------------+
| 2 | root | localhost:3044 | NULL | Sleep | 16858 | | NULL |
| 3 | root | localhost:3052 | uccdb | Sleep | 16788 | | NULL |
| 4 | root | localhost:39029 | NULL | Query | 0 | starting | show processlist |
+----+------+-----------------+-------+---------+-------+----------+------------------+
3 rows in set
Command 爲Sleep的是空閒連接。
值得注意的是
- 空閒連接在特定時間後會失去連接,這個時間參數是
wait_timeout
。
--臨時修改wait_timeout,重啓後失效
set global wait_timeout=28800;--8小時
--也可以通過修改 my.ini 配置文件
- 每一個連接執行操作後,使用的內存是在連接對象中的,直到連接斷開纔會釋放,而重新連接的成本也不低,因此可以在執行大操作後,使用
mysql_reset_connection
(是API不是可執行的SQL)來重置資源。
緩存
在執行查詢語句後,查詢語句以及對應的結果集會被記錄到緩存中,下次遇到同樣的查詢時,直接從緩存中返回即可。
緩存雖然看似可以提高查詢效率,但是在實際應用中卻沒有什麼作用,甚至反而降低了效率。因爲只要某個表更新了數據,那麼這個表相關的緩存就會被清除,如果是更新比較頻繁的業務,那麼緩存幾乎沒有任何作用,反而爲了維護緩存做了更多的無用功。
通常建議關閉緩存,MySQL 8.0 中也已經移除了緩存這個機制。
分析器
分析器有兩個作用,一個是詞法分析,一個是語法分析。
MySQL要知道你給的 SQL 語句是什麼意思,在分析器之前,SQL 語句只是一個字符串而已,分析器要做的首先就是詞法分析,解析 SQL 語句,分析每個單詞的含義,例如開頭select
的,是查詢語句。
分析完單詞的含義之後,接着是語法分析,也就是檢查這句 SQL 語句有沒有語法錯誤。
全部通過後,就將解析後的SQl語句交給優化器。
這裏需要注意的是,分析器除了分析詞法和語法,還會判斷表、字段等是否存在。
優化器
優化器的作用就是要把這句 SQL 語句的執行方案定下來,當然,肯定是優化器認爲的效率最高的那個方案(有的時候優化器並不靠譜)。
經過分析器分析後,MySQL 已經知道你想要做什麼了,此時交給分析器來決定使用哪個索引,如果有多個表的連接查詢,那麼確定先連哪個表。
最後確定了執行計劃後,交給執行器去實施這個計劃。
執行器
執行器階段首先要做的就是判斷送來這個SQL語句的客戶端有沒有權限去執行。
確認有權限執行後,執行器會打開相應的表,根據引擎定義的接口去取數據。這裏以開頭的SQL語句爲例(無索引):
SELECT * FROM student WHERE stu_id = 007;
執行步驟爲:
- 打開表student
- 調用引擎的讀數據接口按順序取一行數據
- 判斷stu_id是否爲007,重複步驟2
- 直到掃描完全表,返回所有符合的數據
至於存在索引的情況,是根據索引的規則來取數據,例如,索引是按stu_id排序的,那麼可以二分查找快速找到對應數據,即合適的索引可以提高查詢效率。