MySQL實(shí)戰(zhàn)45講 學(xué)習(xí)筆記 01 | 基礎(chǔ)架構(gòu):一條SQL查詢語句是如何執(zhí)行的?

MySQL邏輯架構(gòu)圖

MySQL邏輯架構(gòu)圖(出自極客時(shí)間-MySQL實(shí)戰(zhàn)45講)

從圖中就可以看出來MySQL大體架構(gòu)分了兩層,server層和存儲(chǔ)引擎。

server層有管理數(shù)據(jù)庫連接,控制客戶端權(quán)限的連接器、提高查詢性能的查詢緩存、對(duì)SQL語句進(jìn)行解析的分析器、執(zhí)行SQL計(jì)劃生成的優(yōu)化器、根據(jù)計(jì)劃操作存儲(chǔ)引擎接口取數(shù)據(jù)的執(zhí)行器。

存儲(chǔ)引擎則負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)和提取。存儲(chǔ)引擎是插件式的架構(gòu)模式,支持InnoDB,MyISAM、Memory等多個(gè)引擎。



server層

連接器

我們?cè)L問數(shù)據(jù)庫首先接觸的是連接器,連接器負(fù)責(zé)跟客戶端建立連接、獲取權(quán)限、維持、管理連接。連接命令如下:

mysql -h連接地址 -P端口 -u用戶名 -p密碼

如用戶名或密碼不對(duì),會(huì)返回錯(cuò)誤"Access denied for user"的錯(cuò)誤。如正確的話,連接器會(huì)在權(quán)限表里查出你所擁有的權(quán)限。之后,這個(gè)連接里面的權(quán)限判斷邏輯,都將依賴與此時(shí)讀到的權(quán)限。(注意:也就是說,當(dāng)一個(gè)用戶成功建立連接后,權(quán)限的變更不會(huì)影響已經(jīng)存在連接的權(quán)限,只有建立新的連接才會(huì)使用新的權(quán)限設(shè)置。)

查看連接的信息

show processlist

結(jié)果:sleep為空閑的連接

show processlist

客戶端如長時(shí)間沒有動(dòng)靜,連接器會(huì)自動(dòng)斷開,默認(rèn)為8小時(shí),有系統(tǒng)變量 wait_timeout 控制。

客戶端連接在斷開后進(jìn)行請(qǐng)求,會(huì)返回錯(cuò)誤:Lost connection to MySQL server during query。要繼續(xù)執(zhí)行請(qǐng)求必須重連。

在數(shù)據(jù)庫中有長連接和短連接之分,因建立連接的過程比較復(fù)雜,所以應(yīng)當(dāng)減少建立連接的動(dòng)作,也就是盡量使用長連接。

但長連接一直運(yùn)行,資源會(huì)占用越來越多,內(nèi)存會(huì)漲得特別快。只有斷開連接資源才能釋放。

對(duì)于這個(gè)問題,作者給出了兩種方案。

1.?定期斷開長連接,要查詢?cè)僦剡B。

2.?如果MySQL版本是 5.7或更新,可使用mysql_reset_connection函數(shù)來重新初始化連接資源。

查詢緩存

連接建立成功后,第二步就是:查詢緩存。

當(dāng)我們執(zhí)行查詢SQL語句時(shí),會(huì)把SQL語句作為key,結(jié)果集作為value,存入緩存,等下次來請(qǐng)求直接取緩存,就不用后面的復(fù)雜操作了,從而提高性能。但在MySQL8.0之后會(huì)徹底刪除這個(gè)功能。

為什么要?jiǎng)h除?因?yàn)檫@個(gè)功能弊大于利。

1.?要命中緩存,SQL語句必須一模一樣,例如 SELECT id FROM?user 與?select?id?from user就不行,特別是用now()時(shí)間函數(shù),就更加不行了。

2.?當(dāng)一個(gè)表的數(shù)據(jù)有更新時(shí),關(guān)于這個(gè)表所有的緩存都會(huì)被清除,對(duì)于更新頻繁的系統(tǒng)關(guān)掉這個(gè)功能,性能還比開啟要好些,這樣就不會(huì)去查詢判斷是否有緩存。

一般來說查詢緩存用在長時(shí)間不變的靜態(tài)表里面會(huì)比較好。

#MySQL查詢緩存參數(shù) 0關(guān)閉 1打開 2按需求來 表示只要select中明確指定SQL_CACHE才緩存

select SQL_CACHE * from T where ID=10;

show global VARIABLES like 'query_cache_type';

#與查詢緩存相關(guān)的系統(tǒng)變量

#have_query_cache 表示這個(gè)MySQL版本是否支持查詢緩存

#query_cache_limit 表示單個(gè)結(jié)果集所被允許緩存的最大值

#query_cache_min_res_unit 每個(gè)被緩存的結(jié)果集要占用的最小內(nèi)存

#query_cache_size 用于查詢緩存的內(nèi)存大小

show global variables?like 'have_query_cache';

show global variables like 'query_cache_limit';

show global variables like 'query_cache_min_res_unit';

show global variables like 'query_cache_size';

#如何監(jiān)控查詢緩存的命中率

#查詢緩存目前剩余空間大小

show status like 'qcache_free_memory';

#查詢緩存命中次數(shù)

show status like 'qcache_hits';

#查詢未命中時(shí)插入緩存的次數(shù)

show status like 'qcache_inserts';

分析器

分析器做了兩件事情,一件是詞法分析、一件是語法分析。

詞法分析,分析的是每個(gè)字符串是什么意思,比如 select id from T;"select"代表是一個(gè)查詢語句、"id"為一個(gè)列,"T"是一個(gè)表名。

語法分析,分析的是看你的說SQL語句是否符合MySQL的語法,如不符合返回 “You have an error in your SQL syntax” ,一般語法錯(cuò)誤會(huì)提示第一個(gè)出現(xiàn)錯(cuò)誤的位置,所有只要關(guān)注"use near"后面的內(nèi)容。

優(yōu)化器

優(yōu)化器做的是傳過來的SQL語句應(yīng)該怎樣執(zhí)行,以什么樣的順序執(zhí)行,索引怎么選擇。舉一個(gè)栗子:

select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;

像這個(gè)SQL語句就有兩種運(yùn)行模式,一種是從t1表取c列等于10,再關(guān)聯(lián)t2表,再去d列等于20的數(shù)據(jù),還有一種是從t2表d列等于20,再關(guān)聯(lián)t1表,再去取c列等于10的數(shù)據(jù),雖然結(jié)果是一樣的,但效率有所不同。包括表里有多個(gè)索引,索引會(huì)怎么選擇,會(huì)不會(huì)選擇錯(cuò)誤等后面的章節(jié)都會(huì)介紹。

執(zhí)行器

MySQL通過分析器知道你要做什么,優(yōu)化器知道怎么做,接下來就是執(zhí)行了,在執(zhí)行之前會(huì)check一下你有沒有權(quán)限查詢這張表(包括查詢緩存的時(shí)候也會(huì)驗(yàn)證你的權(quán)限),這里有個(gè)問題就是為什么檢查權(quán)限要放在執(zhí)行器來做,而不在分析器的時(shí)候就check掉?作者的回答是:有些時(shí)候,SQL語句要操作的表不只是SQL字面上那些。比如如果有個(gè)觸發(fā)器(觸發(fā)器是由某個(gè)事件激活調(diào)用程序,比如insert、update、delete,可以用來做數(shù)據(jù)同步),得在執(zhí)行器階段(過程中)才能確定。優(yōu)化器階段前是無能為力的。

檢查完權(quán)限后,執(zhí)行器會(huì)調(diào)用引擎里面定義好的接口,去獲取符合條件的數(shù)據(jù),判斷條件從第一行到最后一行(題外話,當(dāng)你獲取的數(shù)據(jù)確定只有一行的時(shí)候,可加上limit 1,這樣就不會(huì)進(jìn)行后面的判斷)。

在數(shù)據(jù)庫的慢查詢?nèi)罩?記錄超過規(guī)定時(shí)間的查詢SQL語句)中有一個(gè)字段叫?rows_examined ,表示在執(zhí)行過程中掃描了多少行,但作者說在有些場景下掃描行數(shù)與這個(gè)字段并不是完全相同的。后面的篇章會(huì)講。

show variables like 'slow_query%';

#是否開啟慢查詢?nèi)罩?/p>

slow_query_log

#慢查詢?nèi)罩疚募刂?/p>

slow_query_log_file

#超過多少秒日志才記錄

show variables like 'long_query_time';

小結(jié)

對(duì)于小編說的不對(duì)的地方請(qǐng)讀者多理解,多包涵,還是推薦大家去看看原文章(極客時(shí)間-MySQL實(shí)戰(zhàn)45講),作者是前阿里資深技術(shù)專家,還是有點(diǎn)東西的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容