【MySQL原理解析】01. 一条SQL查询语句是如何执行的
這是【MySQL原理解析】的第一篇文章,MySQL我看了很多的書與教程,對(duì)其原理有一定的理解,一直想寫一系列的文章來(lái)把MySQL的原理給講清楚,一直沒有時(shí)間寫,今天算是個(gè)開頭吧。萬(wàn)事開頭難,咱們先破了這個(gè)開頭!
MySQL基本架構(gòu)
我們常說,看一件事不要直接陷入細(xì)節(jié),應(yīng)該先從整體框架與流程上把握住,先從最高的維度理解問題,然后再逐步深入各個(gè)模塊。學(xué)習(xí)MySQL也是一樣,在使用MySQL的過程中,我們最開始都是從一條簡(jiǎn)單的查詢語(yǔ)句開始。如在學(xué)生表student中按照學(xué)生的id來(lái)查學(xué)生的信息:
select * from student where id = 100;在我們程序員眼里,這就是一條sql語(yǔ)句,執(zhí)行之后,返回一條結(jié)果。這看起來(lái)很簡(jiǎn)單的過程,實(shí)際在MySQL內(nèi)部,卻是一個(gè)非常復(fù)雜的過程。今天我們就來(lái)把這個(gè)過程拆解出來(lái)。
下面給出的是MySQL的基本架構(gòu)示意圖,從中可以看出SQL語(yǔ)句在MySQL的各個(gè)功能模塊的執(zhí)行過程。
MySQL的基本架構(gòu)可以分為兩大塊,一塊是Server層,一塊是存儲(chǔ)引擎層。
Server層包括連接器、查詢緩存、分析器、優(yōu)化器、執(zhí)行器等。涵蓋了MySQL大多數(shù)的核心服務(wù)功能、以及所有的內(nèi)置函數(shù),所有跨存儲(chǔ)引擎的功能都在這一層實(shí)現(xiàn),比如存儲(chǔ)過程、觸發(fā)器。視圖等。
存儲(chǔ)引擎層負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)與提取。其架構(gòu)模式是插件式的,支持InnoDB、MyISAM、Memmory等多個(gè)存儲(chǔ)引擎。最常用的是InnoDB存儲(chǔ)引擎。所以我們的系列文章也主要是以InnoDB存儲(chǔ)引擎為主。
連接器
在客戶端執(zhí)行上面的查詢語(yǔ)句時(shí),客戶端首先會(huì)與服務(wù)端建立一個(gè)TCP連接,每個(gè)客戶端連接都會(huì)在服務(wù)端進(jìn)程中擁有一個(gè)線程。這個(gè)連接的查詢只會(huì)在這個(gè)單獨(dú)的線程中執(zhí)行,該線程只能輪流在某個(gè)CPU中運(yùn)行。服務(wù)器會(huì)負(fù)責(zé)緩存線程,因此不需要為每一個(gè)新建的連接創(chuàng)建或者銷毀線程。在連接的過程中還涉及到一些安全校驗(yàn)與權(quán)限校驗(yàn)等。
連接成功后,如果沒有后續(xù)的動(dòng)作,這個(gè)連接就處于空閑的狀態(tài),你可以使用 show processlist 命令來(lái)查看線程的各個(gè)狀態(tài)。客戶端如果長(zhǎng)時(shí)間沒有動(dòng)靜,連接器會(huì)自動(dòng)將它斷開。這個(gè)時(shí)間由參數(shù)wait_timeout控制,一般是8小時(shí)。如果在連接被斷開后,客戶端再次發(fā)送請(qǐng)求的話,就會(huì)收到一個(gè)錯(cuò)誤提醒:Lost connection to MySQL server during query。這時(shí)候如果還要繼續(xù)查詢,就要重新建立連接,然后再執(zhí)行請(qǐng)求。
在數(shù)據(jù)庫(kù)領(lǐng)域,長(zhǎng)連接是連接成功后,如果客戶端有請(qǐng)求,則一直使用同一個(gè)連接。短連接則是指每次執(zhí)行完很少的幾次查詢就斷開連接,下次查詢?cè)僦匦陆⒁粋€(gè)。
我們知道TCP建立連接的過程都是非常復(fù)雜的,所以應(yīng)該降低建立連接這個(gè)動(dòng)作,也就是盡量使用長(zhǎng)連接。但是全部使用長(zhǎng)連接后,有可能也會(huì)導(dǎo)致MySQL占用內(nèi)存特別快,這是因?yàn)镸ySQL在執(zhí)行的過程中,臨時(shí)使用的內(nèi)存都是管理在連接對(duì)象里的。這些臨時(shí)使用的內(nèi)存在斷開連接才會(huì)被釋放。所以如果長(zhǎng)連接積累下來(lái),可能導(dǎo)致占用內(nèi)存太大,被系統(tǒng)強(qiáng)行殺掉(OOM),異常重啟。
想要使用長(zhǎng)連接,并且還要解決這種OOM問題的話,可以考慮以下兩種方案。
查詢緩存
連接建立成功后,就可以進(jìn)行select查詢語(yǔ)句了。MySQL拿到一個(gè)查詢請(qǐng)求后,會(huì)先到查詢緩存看看之前是否有過一樣的查詢,如果有則直接返回結(jié)果。如果沒有,才會(huì)進(jìn)行后面的操作。
我們可以看到,查詢緩存如果命中,就不會(huì)走后面的分析器、優(yōu)化器以及存儲(chǔ)引擎提取數(shù)據(jù)了。但是存儲(chǔ)引擎在最新的MySQL8.0版本中已經(jīng)不再支持查詢緩存的功能了。為什么呢?
因?yàn)椴樵兙彺媸Х浅nl繁,只要有對(duì)一個(gè)表的更新操作,這個(gè)表上所的查詢緩存都會(huì)被清空。因此很可能你費(fèi)勁的把緩存建立起來(lái),還沒使用呢,就被一個(gè)更新全清空了。對(duì)于更新壓力大的數(shù)據(jù)庫(kù)來(lái)說,查詢緩存的命中率會(huì)非常低。
分析器
解析器說白了就是對(duì)你輸入的sql語(yǔ)句的解析,解析成MySQL這個(gè)服務(wù)端程序能夠識(shí)別的代碼。解析的過程中肯定會(huì)有判斷sql語(yǔ)句是否正確的語(yǔ)法解析的過程。如果你的語(yǔ)法不對(duì),肯定會(huì)報(bào)錯(cuò)。這個(gè)過程的原理涉及到詞法分析樹與語(yǔ)法分析樹,較為復(fù)雜,這里暫時(shí)不深究。
優(yōu)化器
經(jīng)過分析器解析出MySQL能夠識(shí)別出的代碼后,優(yōu)化器會(huì)對(duì)這部分查詢代碼做一系列的算法優(yōu)化,包括重寫查詢、決定表的讀取順序,以及選擇合適的索引等。用戶可以通過特殊的關(guān)鍵字提示(hint)優(yōu)化器,影響它的決策過程。也可以請(qǐng)求優(yōu)化器解釋(explain)優(yōu)化過程的各個(gè)因素,使用戶可以知道服務(wù)器是如何進(jìn)行優(yōu)化決策的。
對(duì)于優(yōu)化器有哪些優(yōu)化方法來(lái)優(yōu)化查詢,在后面的章節(jié)我們會(huì)詳細(xì)說明。
執(zhí)行器
MySQL通過分析器知道了你要做什么,通過優(yōu)化器知道了該如何做,接下來(lái)就該真正的開始執(zhí)行了。
在開始執(zhí)行的時(shí)候,MySQL會(huì)再次判斷本次查詢是否對(duì)要查詢的表有執(zhí)行查詢的權(quán)限,如果沒有會(huì)報(bào)錯(cuò)。如果有權(quán)限就打開表繼續(xù)執(zhí)行。打開表的時(shí)候,執(zhí)行器會(huì)根據(jù)這個(gè)表所使用的存儲(chǔ)引擎,選擇對(duì)應(yīng)的存儲(chǔ)引擎接口。
小結(jié)
本篇文章主要講解了MySQL的基本架構(gòu),MySQL的整體架構(gòu)還是非常復(fù)雜的,我們能夠?qū)ySQL的基本架構(gòu)搞懂就行。這次主要學(xué)會(huì)一條查詢語(yǔ)句,大致需要經(jīng)歷哪些流程,經(jīng)過了哪些模塊,每一個(gè)模塊的細(xì)化流程都相當(dāng)復(fù)雜,我們也不必把每一個(gè)模塊都搞懂。作為一名后端開發(fā)人員,將優(yōu)化器與存儲(chǔ)引擎層的相關(guān)原理搞懂就可以。
在后面的章節(jié),我們會(huì)深入學(xué)習(xí)優(yōu)化器與存儲(chǔ)引擎相關(guān)原理!
總結(jié)
以上是生活随笔為你收集整理的【MySQL原理解析】01. 一条SQL查询语句是如何执行的的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: stata15中文乱码_Stata15:
- 下一篇: mysql 慢sql分析_如何分析Mys