mysql,是我們經常用到的數據庫,而我們平時所用到的操作,大多是輸入一條sql,然后獲取返回結果。例如:
select * from t where id = 1;
基本上不會關注mysql內部的執行流程。
基礎架構:
下面我們就簡單的說一下mysql的基本架構,從而簡單的窺探一番sql的基本流程。
下面是mysql的基本架構圖:
mysql大體上可以分為Server層和存儲引擎。
server層包含連接器、查詢緩存、解析器、優化器、執行器等,涵蓋了mysql的基本核心功能和所有內置函數(日期、時間、數學和加密函數等),所有跨存儲引擎的功能都在這一層實現,比如存儲過程、觸發器、視圖等。
存儲引擎負責數據的存儲和提取,架構是插件式的,支持InnoDB、MyISAM、Memory等。目前最常用的是InnoDB,從mysql5.5開始成為了默認引擎。創建表時,可以通過指定引擎類型來選擇引擎,比如
CREATE TABLE t
(
id VARCHAR(40)
) ENGINE=INNODB DEFAULT CHARSET=utf8 ;#指定引擎和存儲字符類型
下面簡單介紹一下server層各個組件的作用。
連接器
連接器是你連接到數據庫的第一個接待者。連接器負責跟客戶端建立連接、獲取權限、維持和管理連接。連接命令如下:
mysql -h$ip -P$port -u$user -p;
密碼可以寫在-p后面的命令行中,為安全起見,強烈建議不要這么做。
mysql客戶端和服務端建立連接,完成經典的TCP握手協議后,連接器就開始驗證身份,這時候就需要輸入密碼。
- 如果用戶名密碼不匹配,返回"Access denied for user"的錯誤。
- 如果密碼驗證通過,連接器會去權限表查詢你所擁有的權限。之后這個連接里的權限判斷邏輯,都會依賴于此時讀到的邏輯。這意味著,如果更改了這個用戶的權限,是不會影響到已經建立的連接。新的連接才會讀取到新的權限
連接完成后,如果你沒有后續的動作,這個連接就處于空閑狀態可以使用show processlist
命令查看。其中Command顯示Sleep的這一行表示的有多少個空閑的連接。
如果客戶端太長時間沒有動作,連接器會自動斷開連接,這個時間默認是8小時,可以進行配置。
建立連接的過程是有一定開銷的,會因此建議在使用中盡量使用長連接。
但全部使用長連接后,有時候會發現mysql的內存占用漲的特別快。
這是因為mysql在執行過程中的臨時內存是管理在連接對象里面的,這些資源在連接斷開的時候才會釋放(不太理解,待后續查證)
查詢緩存
建立連接之后,就可以執行select語句了,執行邏輯第二步:查詢緩存。
但是這個緩存使用往往弊大于利。因為緩存的失效非常頻繁,只要有對一個表的更新,這個表上所有的緩存都會被清空。mysql8.0之后已經徹底刪除這塊功能了。不再贅述。
解析器
執行語句,首先要知道語句要做什么,因此需要對語句做解析。如果你的語句語法不正確,會受到You have an error in your SQL syntax
的錯誤提醒。
優化器
在開始執行sql之前,mysql還會對語句進行優化處理。
- 優化器在表里有多個索引的時候,決定使用哪個索引
- 多表關聯的時候,決定表的連接順序
例如join語句:
select * from t1 join t2 using(id) where t1.c = 10 and t2.d = 20;
既可以先從t1中取出c=10的記錄,在根據id關聯t2,然后再判斷t2.d是否等于20;也可以先從t2中取出d=20的記錄關聯t1,再判讀t1.c是否滿足。
優化器決定使用哪一種方案。
執行器
開始執行的時候,優先要判斷是否對這個表有權限,如果沒有們就會返回錯誤。
查詢流程中,如果id沒有索引,那么順序是這樣的:
1. 調用InnoDB引擎接口獲取表的第一行,然后判斷id是否是1,如果不是則跳過,如果是則將結果存在結果集中;
2. 調用引擎接口獲取“下一行”,重復判斷邏輯,直至最后一行。
3. 執行器將遍歷結果組成的記錄集返回給客戶端。
對于有索引的表,執行邏輯類似,第一次調用“取滿足條件的第一行”,之后循環取“滿足條件的下一行”這個接口。
在慢查詢語句中有個rows_examined
的字段,這個值是執行器調用引擎獲取數據行的時候累加的。有些場景下,執行器調用一次,引擎內部會掃描多行,因此引擎掃描行數跟rows_examined
并不是完全相同的。
(注:部分內容來源于網路和一些學習資料,并非本人原著)