回復(fù)“面試”獲取全套面試資料
字?jǐn)?shù):3620,閱讀耗時(shí):4分35秒
最近群里一位兄弟在面試中被問到:「MySQL的架構(gòu)體系是什么」。
雖然他搞java開發(fā)好幾年了,也一直使用的是MySQL數(shù)據(jù)庫,但是面對(duì)這個(gè)問題依然是一臉懵逼,還以為面試官要問索引、慢查詢、性能優(yōu)化之類的(因?yàn)檫@些都是網(wǎng)上找點(diǎn)面試題背過了)。
但這位面試官不按套路出牌,這位兄弟當(dāng)場就是臉紅耳赤的,心想nnd居然會(huì)這么問。其實(shí)面試中面試官的問題有千千萬,有的問題確實(shí)背背面試題就能應(yīng)對(duì),但不是所有的面試題咱們都能背下來的。
今天我們就來聊聊MySQL的架構(gòu)體系,盡管咱們是java開發(fā)人員,但是在日常開發(fā)過程中也會(huì)經(jīng)常和MySQL數(shù)據(jù)庫打交道。如果公司有DBA能干點(diǎn)事還稍微好點(diǎn),如果是沒有DBA或者DBA沒什么卵用的情況下,我們還是很有必要了解MySQL的整個(gè)體系的,況且在面試中遇到了也是一個(gè)加分項(xiàng)。
想要知道一條SQL是怎么查詢的,只要對(duì)MySQL整個(gè)體系搞清楚了,才能說出個(gè)123。
所以于情于理,我們很有必要學(xué)習(xí)一下MySQL的架構(gòu)體系的。
平時(shí),和小伙伴們聊天的時(shí)候,經(jīng)常會(huì)把MySQL當(dāng)做我們開發(fā)的一個(gè)軟件系統(tǒng),既然是軟件系統(tǒng),那么就有個(gè)架構(gòu)圖,以及架構(gòu)是如何分層的,每一層的功能是什么。
下面我們就來看看MySQL的整體架構(gòu)圖。
再來看看我們開發(fā)的系統(tǒng)架構(gòu)圖:
其實(shí)還是蠻相似的。都有分層的概念。既然我們開發(fā)的軟件系統(tǒng)能進(jìn)行分層,那么MySQL能分層嗎?
答案是:能,下面我們就來聊聊MySQL的分層情況以及每一層的功能。
上面的架構(gòu)圖我們可以對(duì)其進(jìn)行拆分,并做簡要的說明。
與客戶端打交道,上面已經(jīng)寫明了能支持的的語言。客戶端的鏈接支持的協(xié)議很多,比如我們?cè)?Java 開發(fā)中的 JDBC。
主要是負(fù)責(zé)存儲(chǔ)和管理客戶端與數(shù)據(jù)庫的鏈接,一個(gè)線程負(fù)責(zé)管理一個(gè)連接。自從引入了連接池以后,官方報(bào)道:當(dāng)數(shù)據(jù)庫的連接數(shù)達(dá)到128后,使用連接池與沒有連接池的性能是提升了n倍(反正就是性能大大的提升了)。
連接建立完成后,就可以執(zhí)行select語句了。執(zhí)行邏輯就會(huì)先來到緩存模塊。
MySQL拿到一個(gè)查詢請(qǐng)求后,會(huì)先到查詢緩存看看,之前是不是執(zhí)行過這條語句。之前執(zhí)行過的語句及其結(jié)果會(huì)以key-value對(duì)的形式存儲(chǔ)在內(nèi)存中。key是查詢的語句,value是查詢的結(jié)果。如果你的查詢能夠直接在這個(gè)緩存中找到key(命中),那么這個(gè)value就會(huì)被直接返回給客戶端。
如果在緩存中未命中,就會(huì)繼續(xù)后面的執(zhí)行階段。執(zhí)行完成后,執(zhí)行結(jié)果會(huì)被存入查詢緩存中。這里可以看到,如果查詢命中緩存,MySQL不需要執(zhí)行后面的復(fù)雜操作,就可以直接返回結(jié)果,這個(gè)效率會(huì)很高。
但是大多數(shù)情況下我會(huì)建議你不要使用查詢緩存,為什么呢?因?yàn)椴樵兙彺嫱状笥诶?/p>
查詢緩存的失效非常頻繁,只要有對(duì)一個(gè)表的某一條數(shù)據(jù)更新,這個(gè)表上所有的查詢緩存都會(huì)被清空。
因此可能很費(fèi)勁地把結(jié)果存起來,還沒使用呢,就被一個(gè)更新全清空了。對(duì)于更新壓力大的數(shù)據(jù)庫來說,查詢緩存的命中率會(huì)非常低。除非你的業(yè)務(wù)就是有一張靜態(tài)表,很長時(shí)間才會(huì)更新一次。
比如:一個(gè)系統(tǒng)配置表,那這張表上的查詢才適合使用查詢緩存。
好在MySQL也提供了這種“按需使用”的方式。你可以將參數(shù)query_cache_type設(shè)置成DEMAND,這樣對(duì)于默認(rèn)的SQL語句都不使用查詢緩存。
「注意」:MySQL 8.0版本直接將查詢緩存的整塊功能刪掉了,標(biāo)志著MySQL8.0開始徹底沒有緩存這個(gè)功能了。
如果沒有命中查詢緩存,就要開始真正執(zhí)行語句了。首先,MySQL需要知道你要做什么,因此需要對(duì)SQL語句做解析。
分析器先會(huì)做“詞法分析”。你輸入的是由多個(gè)字符串和空格組成的一條SQL語句,MySQL需要識(shí)別出里面的字符串分別是什么,代表什么。
做完了詞法分析以后,就要做“語法分析”。根據(jù)詞法分析的結(jié)果,語法分析器會(huì)根據(jù)語法規(guī)則,判斷你輸入的這個(gè)SQL語句是否滿足MySQL語法。
如果我們?cè)谄磳慡QL時(shí)候,少了或者寫錯(cuò)了某個(gè)字母,,就會(huì)收到“You have an error in your SQL syntax”的錯(cuò)誤提醒。
比如下面這個(gè)案例:
錯(cuò)誤在于WHERE關(guān)鍵字中差了一個(gè)E。
同樣,我們使用的SQL如果某個(gè)字段不存在。
一般語法錯(cuò)誤會(huì)提示第一個(gè)出現(xiàn)錯(cuò)誤的位置,所以你要關(guān)注的是緊接“use near”的內(nèi)容,僅供參考,有時(shí)候這個(gè)提示也不是非常靠譜。
經(jīng)過分析器對(duì)SQL進(jìn)行了分析,并且沒有報(bào)錯(cuò)。那么此時(shí)就進(jìn)入優(yōu)化器中,對(duì)SQL進(jìn)行優(yōu)化。
優(yōu)化器主要是在我們的數(shù)據(jù)庫表中,如果存在多個(gè)多個(gè)索引的時(shí)候,決定使用哪個(gè)索引;或者在一個(gè)語句有多表關(guān)聯(lián)(join)的時(shí)候,決定各個(gè)表的連接順序 。
比如說:
SELECT a.id, b.id FROM t_user a join t_user_detail b WHERE a.id=b.user_id and a.user_name='田維常' and b.id=10001
它會(huì)在條件查詢上進(jìn)行優(yōu)化處理。
優(yōu)化器處理完成過后,此時(shí)就已經(jīng)確定了SQL的執(zhí)行方案。然后繼續(xù)進(jìn)入執(zhí)行器中。
首先,肯定是要判斷權(quán)限,就是有沒有權(quán)限執(zhí)行這條SQL。工作中可能會(huì)對(duì)某些客戶端進(jìn)行權(quán)限控制。
比如說:生產(chǎn)環(huán)境中,對(duì)于大部分開發(fā)人員都只開查詢權(quán)限,沒有增刪改權(quán)限(部分小公司除外)。
如果有權(quán)限,就打開表繼續(xù)執(zhí)行。打開表的時(shí)候,執(zhí)行器就會(huì)根據(jù)表的引擎定義,去使用這個(gè)引擎提供的接口。
存儲(chǔ)引擎的概念是MySQL里面才有的,不是所有的關(guān)系型數(shù)據(jù)庫都有存儲(chǔ)引擎這個(gè)概念 。
數(shù)據(jù)庫存儲(chǔ)引擎是數(shù)據(jù)庫底層軟件組織,數(shù)據(jù)庫管理系統(tǒng)(DBMS)使用數(shù)據(jù)引擎進(jìn)行創(chuàng)建、查詢、更新和刪除數(shù)據(jù)。不同的存儲(chǔ)引擎提供不同的存儲(chǔ)機(jī)制、索引技巧、鎖定水平等功能,使用不同的存儲(chǔ)引擎,還可以獲得特定的功能?,F(xiàn)在許多不同的數(shù)據(jù)庫管理系統(tǒng)都支持多種不同的數(shù)據(jù)引擎。
因?yàn)樵陉P(guān)系數(shù)據(jù)庫中數(shù)據(jù)的存儲(chǔ)是以表的形式存儲(chǔ)的,所以存儲(chǔ)引擎也可以稱為表類型(Table Type,即存儲(chǔ)和操作此表的類型)。
下面對(duì)部分相對(duì)使用多的引擎進(jìn)行一個(gè)對(duì)比:
在實(shí)際項(xiàng)目中,大多數(shù)使用InnoDB,然后是MyISAM,至于其他存儲(chǔ)引擎使用的非常至少。
Mysql5.5 版本之前默認(rèn)的存儲(chǔ)引擎就是 MyISAM 存儲(chǔ)引擎,MySQL 中比較多的系統(tǒng)表使用 MyISAM 存儲(chǔ)引擎,系統(tǒng)臨時(shí)表也會(huì)用到 MyISAM 存儲(chǔ)引擎,但是在 Mysql5.5 之后默認(rèn)的存儲(chǔ)引擎就是 InnoDB 存儲(chǔ)引擎了。
兩個(gè)主要原因:
系統(tǒng)文件存儲(chǔ)層主要是負(fù)責(zé)將數(shù)據(jù)庫的數(shù)據(jù)和日志存儲(chǔ)在系統(tǒng)的文件中,同時(shí)完成與存儲(chǔ)引擎的之間的打交道,是文件的物理存儲(chǔ)層。
比如:數(shù)據(jù)文件、日志文件、pid文件、配置文件等。
「db.opt文件」:記錄這個(gè)數(shù)據(jù)庫的默認(rèn)使用的字符集和校驗(yàn)規(guī)則。
「frm文件」:存儲(chǔ)于邊相關(guān)的元數(shù)據(jù)信息,包含表結(jié)構(gòu)的定義信息等,每一張表都會(huì)有一個(gè)frm文件與之對(duì)應(yīng)。
「MYD文件」:MyISAM存儲(chǔ)引擎專用的文件,存儲(chǔ)MyISAM表的數(shù)據(jù)信息,每一張MyISAM表都有有一個(gè).MYD文件。
「MYI文件」:也是MyISAM存儲(chǔ)引擎專用的文件,存放MyISAM表的索引相關(guān)信息,每一張MyISAM表都有對(duì)應(yīng)的.MYI文件。
「ibd文件和ibdata文件」:存放InnoDB的數(shù)據(jù)文件(包括索引)。InnoDB存儲(chǔ)引擎有兩種表空間方式:獨(dú)立表空間和共享表空間。
獨(dú)享表空間使用ibd文件來存放數(shù)據(jù),并且每一張InnoDB表存在與之對(duì)應(yīng)的.ibd文件。
共享表空間使用ibdata文件,所有表共同使用一個(gè)或者多個(gè).ibdata文件。
「ibdata1文件」:系統(tǒng)表空間數(shù)據(jù)文件,存儲(chǔ)表元數(shù)據(jù)、Undo日志等。
「ib_logfile0、ib_logfile0文件」:Redo log日志文件。
錯(cuò)誤日志:默認(rèn)是開啟狀態(tài),可以通過命令查看:
show variables like '%log_error%';
二進(jìn)制日志binary log:記錄了對(duì)MySQL數(shù)據(jù)庫執(zhí)行的更改操作,并且記錄了語句的發(fā)生時(shí)間、執(zhí)行耗時(shí);但是不記錄查詢select、show等不修改數(shù)據(jù)的SQL。主要用于數(shù)據(jù)庫恢復(fù)和數(shù)據(jù)庫主從復(fù)制。也是大家常說的binlog日志。
show variables like '%log_log%';//查看是否開啟binlog日志記錄。
show variables like '%binllog%';//查看參數(shù)
show binary logs;//查看日志文件
慢查詢?nèi)罩荆河涗洸樵償?shù)據(jù)庫超時(shí)的所有SQL,默認(rèn)是10秒。
show variables like '%slow_query%';//查看是否開啟慢查詢?nèi)罩居涗洝?br>show variables '%long_query_time%';//查看時(shí)長
通用查詢?nèi)罩荆河涗浺话悴樵冋Z句;
show variables like '%general%';
用于存放MySQL所有的配置信息的文件,比如:my.cnf、my.ini等。
「pid文件」
pid文件是mysqld應(yīng)用程序在Linux或者Unix操作系統(tǒng)下的一個(gè)進(jìn)程文件,和許多其他Linux或者Unix服務(wù)端程序一樣,該文件放著自己的進(jìn)程id。
「socket文件」
socket文件也是Linux和Unix操作系統(tǒng)下才有的,用戶在Linux和Unix操作系統(tǒng)下客戶端連接可以不通過TCP/IP網(wǎng)絡(luò)而直接使用Unix socket來連接MySQL數(shù)據(jù)庫。
SQL查詢流程圖
MySQL整個(gè)系統(tǒng)我們可以看成是我們?nèi)粘i_發(fā)的軟件系統(tǒng),也有接入層,專門對(duì)接外面客戶端的,和我們系統(tǒng)的網(wǎng)關(guān)就很像,緩存也就類似我們業(yè)務(wù)代碼中使用的緩存,解析器可以理解為業(yè)務(wù)系統(tǒng)中參數(shù)解析以及參數(shù)校驗(yàn),優(yōu)化層可以當(dāng)做我們開發(fā)代碼優(yōu)化的手段,然后存儲(chǔ)引擎就相當(dāng)于我們的持久層,文件系統(tǒng)相當(dāng)于整個(gè)業(yè)務(wù)系統(tǒng)中的數(shù)據(jù)庫。
可能比喻不是非常的恰當(dāng),但是希望大家能領(lǐng)略輕重的含義,目的只有一個(gè),那就是讓大家能輕松掌握MySQL的整體情況。
不要天天羨慕什么大牛,什么大神,他們也是一步一步來的(個(gè)例除外)。自信點(diǎn),只要你一點(diǎn)一點(diǎn)搞,踏踏實(shí)實(shí)的干,你也會(huì)成為大神的。
聯(lián)系客服