有一個(gè)數(shù)據(jù)表炼蹦,只有ID屬性列,以
select * from T where ID = 10
為例
先看一張Mysql的架構(gòu)圖显设,如下:
連接器
第一步框弛,需要連接到數(shù)據(jù)庫(kù)上,這個(gè)時(shí)候接待我們的就是連接器捕捂,連接器負(fù)責(zé)根客戶端建立連接瑟枫、獲取權(quán)限、維持和管理連接
一般連接命令如下:
mysql -h$ip -P$port -u$user -p
輸完命令后指攒,就需要在交互對(duì)話框輸入密碼慷妙。
連接命令中的mysql是客戶端工具,用來(lái)根服務(wù)器建立連接允悦,在完成經(jīng)典的TCP握手后膝擂,連接器就開(kāi)始認(rèn)證我們的身份,這個(gè)時(shí)候用的就是輸入的用戶名和密碼隙弛。
- 如果用戶名或者這密碼不對(duì)架馋,會(huì)產(chǎn)生一個(gè)"Access denied for user"的錯(cuò)誤,然后客戶端程序執(zhí)行結(jié)束
- 如果用戶名密碼認(rèn)證通過(guò)全闷,連接器會(huì)到權(quán)限表里面查出你擁有的權(quán)限叉寂,之后再鏈接里的權(quán)限判斷邏輯,都將以來(lái)此時(shí)讀到的權(quán)限总珠。這就意味著屏鳍,一個(gè)用戶成功建立連接后,即便管理員對(duì)這個(gè)用戶的權(quán)限做了修改局服,也不會(huì)影響到已經(jīng)存在的連接權(quán)限钓瞭。修改完成后,只有再次建立新的連接才會(huì)使用新的權(quán)限設(shè)置淫奔。
連接完成后山涡,如果你沒(méi)有后續(xù)的動(dòng)作,這個(gè)連接就處于空閑狀態(tài)唆迁,可以使用show processlist查看佳鳖,其中Command為Sleep對(duì)的表示,現(xiàn)在這個(gè)連接是空閑的媒惕。
如果客戶端太長(zhǎng)沒(méi)動(dòng)靜,連接器就會(huì)自動(dòng)將它斷開(kāi)来庭,這個(gè)參數(shù)時(shí)候wait_timeout控制的妒蔚。默認(rèn)是8小時(shí)
如果在連接被斷開(kāi)之后,客戶端再次發(fā)送請(qǐng)求的話,就會(huì)收到一個(gè)Lost connection toMYSQL server during query肴盏。這個(gè)時(shí)候需要重連科盛。
數(shù)據(jù)庫(kù)里面,長(zhǎng)連接是指連接成功后菜皂,如果客戶端持續(xù)有請(qǐng)求贞绵,則一直使用同一個(gè)連接。短鏈接則是指每次執(zhí)行完很少的幾次查詢就斷開(kāi)連接恍飘,下次查詢尋再重新連級(jí)一個(gè)
在全部使用長(zhǎng)連接之后榨崩,MYSQ占用內(nèi)存漲的特別快,這是因?yàn)镸YSQL在執(zhí)行過(guò)程中臨時(shí)使用的內(nèi)存是管理在連接對(duì)象倆面的章母。這些資源只有在斷開(kāi)的時(shí)候才會(huì)釋放母蛛。所以如果行i攔截積累下來(lái)可能會(huì)導(dǎo)致占用內(nèi)存太大,從而被系統(tǒng)強(qiáng)行殺掉(OOM Out Of Memory)乳怎,從表現(xiàn)看來(lái)就是MYSQL異常重啟了彩郊。
解決方案如下:
- 定期斷開(kāi)長(zhǎng)連接。使用一段時(shí)間或者程序里面判斷執(zhí)行過(guò)一個(gè)占用內(nèi)存的大查詢之后斷開(kāi)連接蚪缀。
- 如果使用5.7+版本之后秫逝,可以在每次執(zhí)行一個(gè)較大的操作之后,通過(guò)mysql_reset_connection來(lái)重新初始化連接資源询枚。這個(gè)過(guò)程不需要重連和重新做權(quán)限驗(yàn)證违帆,但是會(huì)將連接恢復(fù)到剛剛創(chuàng)建完的狀態(tài)
查詢緩存
連接建立完之后,就可以執(zhí)行select雅居樂(lè)哩盲,執(zhí)行邏輯會(huì)來(lái)到第二步:查詢緩存痹仙。
Mysql拿到一個(gè)查詢請(qǐng)求之后,會(huì)先到查詢緩存看看饵撑,之前是不是執(zhí)行過(guò)這條sql語(yǔ)句撩笆。執(zhí)行執(zhí)行語(yǔ)句及其結(jié)果會(huì)以Key-value對(duì)的形式,被直接緩存到內(nèi)存中抒线。key是查詢的語(yǔ)句班巩,value是結(jié)果,如果能夠直接在緩存中找到查詢尋語(yǔ)句嘶炭,那么會(huì)直接將value返回
如果不存在會(huì)繼續(xù)執(zhí)行后面的階段 抱慌,執(zhí)行完成之后結(jié)果會(huì)被存到緩存中,雖然查詢尋緩存命中之后眨猎,效率極高抑进,但總的來(lái)說(shuō)弊大于利
緩存的失效非常頻繁,一位內(nèi)只要對(duì)一個(gè)表有更新睡陪,這個(gè)表的所有查詢緩存都會(huì)被清空
從mysql.8.0開(kāi)始將查詢緩存整塊功能都刪掉了
分析器
如果沒(méi)有名中查詢緩存寺渗,就要開(kāi)始真正執(zhí)行語(yǔ)句了匿情。首先mysql需要知道我們是要做什么,因此需要對(duì)SQL語(yǔ)句做解析信殊。分析器首先會(huì)做“詞法分析”炬称,SQL語(yǔ)句是由多個(gè)字符串和空格組成的,MySQL需要識(shí)別出里面的字符串分別是什么表示什么涡拘。做完了這些后就會(huì)進(jìn)行語(yǔ)法分析玲躯,根據(jù)詞法分析的結(jié)果,語(yǔ)法分析器會(huì)根據(jù)語(yǔ)法規(guī)則鳄乏,判斷這個(gè)sql語(yǔ)句是否滿足mysql語(yǔ)法
在分析語(yǔ)法的時(shí)候同時(shí)會(huì)分析索要查詢的列是否存在跷车,因?yàn)楸斫Y(jié)構(gòu)并不是需要打開(kāi)表才能看到的,因此對(duì)列是否存在的分析也是在這一步完成的
優(yōu)化器
經(jīng)過(guò)了分析器汞窗,mysql就能知道需要做什么了姓赤、優(yōu)化器是在表里面有多個(gè)索引的時(shí)候,決定使用哪個(gè)索引仲吏;或者在一個(gè)語(yǔ)句有多表關(guān)聯(lián)(join)的時(shí)候不铆,決定各個(gè)表的連接順序,如下語(yǔ)句
select * from t1 join using(ID) where t1.c=10 and t2.d = 20;
既可以先從t1表里面取出c=10的記錄ID值裹唆,再根據(jù)t2里面d值怕判斷是否等于20
也可以先從t2表里面取出d=20的記錄id值誓斥,在根據(jù)id值關(guān)聯(lián)到t1,在判斷t1里面的c是否等于10
這兩種執(zhí)行方法的邏輯結(jié)果是一樣的许帐,但是執(zhí)行的效率會(huì)有不同劳坑,而優(yōu)化器的作用是決定選擇使用哪一個(gè)方案。
優(yōu)化器階段完成后成畦,這個(gè)語(yǔ)句的執(zhí)行方案就確定下來(lái)了距芬,接下來(lái)進(jìn)入執(zhí)行器階段。
執(zhí)行器
mysql通過(guò)分析器知道要做什么循帐,通過(guò)優(yōu)化器知道要怎么做框仔,接下來(lái)就進(jìn)入執(zhí)行器,開(kāi)始執(zhí)行SQL語(yǔ)句
開(kāi)始執(zhí)行的時(shí)候拄养,要先判斷一下當(dāng)前用戶是否有對(duì)這個(gè)表T的執(zhí)行查詢權(quán)限离斩,但是如果在命中緩存的時(shí)候,會(huì)在將緩存放回結(jié)果的時(shí)候進(jìn)行權(quán)限驗(yàn)證
如果有權(quán)限那么就打開(kāi)表繼續(xù)執(zhí)行瘪匿,跛梗。打開(kāi)表的時(shí)候,執(zhí)行器就會(huì)根據(jù)表的殷勤定義棋弥,去使用引擎提供的接口核偿。
比如本例中,ID字段沒(méi)有索引顽染,那么執(zhí)行器的執(zhí)行流程如下:
- 調(diào)用InnoDB引擎接口獲取表的第一行根據(jù)條件判斷ID是否為10宪祥,如果不是則跳過(guò)聂薪,如果是則將這一行緩存到結(jié)果集中
- 調(diào)取引擎接口獲取下一行,直到這個(gè)表的最后一行蝗羊。
- 執(zhí)行器將上述遍歷過(guò)程中所有滿足條件的記錄集作為結(jié)果集返回給客戶端。
至此一個(gè)語(yǔ)句就執(zhí)行完了