# 快速拉起一臺MySQL 8.0Docker容器,生產(chǎn)切勿這樣拉取,需要把數(shù)據(jù)目錄都掛載出來,這里我們只不過是為了研究MySQL,所以就不掛載了。
docker run --name mysql-8.0.27 -p 3306:3306 -e MYSQL_ROOT_PASSword=123456 -d mysql:8.0.27
MySQL整體架構(gòu)分為哪兩部分?
- Server層:大多數(shù)的核心服務(wù)功能、所有的內(nèi)置函數(shù)等一些跨存儲引擎的功能
- 存儲引擎層:負(fù)責(zé)數(shù)據(jù)的存儲和讀取
MySQL的存儲引擎主要有哪幾種?
- InnoDB:MySQL 5.5.5版本以后是默認(rèn)引擎
- MyISAM
- Memory
在create table的時候可以指定引擎類型(engine=InnoDB|MyISAM|Memory),不同存儲引擎的表數(shù)據(jù)存儲方式也不一致。
MySQL Server層主要包含哪些組件?
- 連接器
- 查詢緩存
- 分析器
- 優(yōu)化器
- 執(zhí)行器
連接器
連接器的作用是?
連接器負(fù)責(zé)和客戶端建立連接、獲取權(quán)限、維持和管理連接。
# 連接mysql
mysql -h 127.0.0.1 -P 3306 -u root
- 客戶端首先和連接器通過TCP握手建立連接
- 對用戶輸入的用戶名和密碼進(jìn)行驗證
- 驗證失敗會返回ERROR 1045 (28000): Access denied for user 'test'@'172.17.0.1' (using password: YES)錯誤
- 驗證通過以后,連接器會到權(quán)限表里面查處用戶擁有的權(quán)限。之后連接里面的權(quán)限邏輯判斷。都依賴于此時讀到的權(quán)限
注意這里的權(quán)限的修改一定要使用grant語句,不要手動改表,因為grant語句可以刷新內(nèi)存,權(quán)限會立即更新,但是如果手動改表,權(quán)限不會刷新內(nèi)存,內(nèi)存里面的權(quán)限依舊是舊的。
如果手動改表的話請記得一定要跟上flush privileges這個SQL語句刷新內(nèi)存。
權(quán)限表在哪里?
- 全局權(quán)限:mysql.user表
- 數(shù)據(jù)庫層級:mysql.db表
- 表層級:mysql.tables_priv表
- 列層級:mysql.columns_priv表
連接建立長時間無活動,連接器會怎么處理?
連接在建立后,如果客戶端太長時間沒有活動,連接器會自動將它斷開,該時間由wait_timeout和interactive_timeout參數(shù)控制,默認(rèn)都是8小時。
- wait_timeout:非交互式連接的空閑超時
- interactive_timeout:交互式連接的空閑超時(程序連接MySQL Server為交互連接)
這兩個參數(shù)盡量設(shè)置為一樣的值。連接在被斷開以后,客戶端再次發(fā)送請求的話,會收到以下響應(yīng):
ERROR 4031 (HY000): The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.
什么是長連接?
長連接是指連接建立成功以后,如果客戶端持續(xù)有請求就一直使用該連接,短連接每次執(zhí)行完很少查詢就會斷開連接,下次需要重新建立。
數(shù)據(jù)庫為什么連接使用長連接?
連接建立過程相對復(fù)雜耗時,因此在使用過程中盡量減少連接的建立次數(shù),使用長連接。
長連接的弊端是?
MySQL內(nèi)存增長快速。
因為MySQL在執(zhí)行過程中臨時使用的內(nèi)存時管理在連接對象里面的,這些資源需要在斷開連接的時候才可以釋放。如果長連接累積下來會導(dǎo)致內(nèi)存占用太大被系統(tǒng)強行殺掉。
如何解決長連接的弊端?
- 定時斷開長連接:使用一段時間或者程序判斷執(zhí)行一個占用內(nèi)存的大查詢后斷開連接,之后再重連
- mysql_reset_connection:在每次執(zhí)行較大的操作后,執(zhí)行mysql_reset_connection來重新初始化連接資源。該過程不需要重連,只是將連接恢復(fù)到剛創(chuàng)建完時的狀態(tài)。
mysql_reset_connection是為各個編程語言提供的API,不是SQL語句。
查詢緩存
MySQL獲得查詢請求后,會先查詢緩存,如果緩存中有直接返回,否則往下執(zhí)行。
緩存中的key是查詢的語句,value是結(jié)果。
對表上的更新,會讓該表所有的緩存全部失效。
大多數(shù)情況下不建議使用緩存,緩存的弊遠(yuǎn)遠(yuǎn)大于利。MySQL8.0以后直接把查詢緩存的功能進(jìn)行了移除。
分析器
MySQL Server在拿到SQL語句以后,需要知道這條語句干什么。
select id from test;
- 分析器做詞法分析:需要把一長串字符串進(jìn)行識別,比如上述語句需要將select識別出來,這是一個查詢語句;test是表名,id是列名
- 詞法分析完成以后會做語法分析,語法分析器會根據(jù)語法規(guī)則判斷該SQL語句是否合法
這里還會對查的列和表是否存在做校驗(語義分析)。
優(yōu)化器
在經(jīng)過分析器以后,MySQL Server已經(jīng)知道想要干啥,但是怎么干,如何干才能更快,此時就需要借助優(yōu)化器了。
優(yōu)化器會在有多個索引時決定使用哪個索引,或者有多表關(guān)聯(lián)時決定各個表的連接順序。
執(zhí)行器
MySQL Server通過分析器知道要干啥,通過優(yōu)化器知道怎么干,于是到達(dá)了執(zhí)行器開始干。
但是在開始干之前需要檢查一下權(quán)限,如果權(quán)限校驗不通過就會返回沒有權(quán)限的錯誤,如下圖:
如果權(quán)限校驗通過,就打開表繼續(xù)執(zhí)行。打開表會根據(jù)表的引擎定義去調(diào)用引擎提供的接口。
select * from test where id = 1;
假設(shè)上述表沒有索引,引擎是InnoDB,執(zhí)行器會這樣操作:
- 調(diào)用InnoDB引擎接口獲取表的"第一行",判斷ID是否為1,如果不是則跳過,是就將這一行存入結(jié)果集
- 調(diào)用引擎接口取"下一行",重復(fù)第一步的邏輯判斷,直到取完表的"最后一行"
- 執(zhí)行器將滿足條件的行的結(jié)果集返回給客戶端。
執(zhí)行器調(diào)用一次,引擎內(nèi)部可能會掃描多行。






