MySQL最常問的十道面試題(2023年最新詳解版)
1.什么是聚集索引和非聚集索引
簡單來說,聚集索引就是基于主鍵創(chuàng)建的索引,除了主鍵索引以外的其他索引,稱為非聚集索引,也叫做二級索引。
- 由于在InnoDB引擎里面,一張表的數(shù)據(jù)對應(yīng)的物理文件本身就是按照B+樹來組織的一種索引結(jié)構(gòu),而聚集索引就是按照每張表的主鍵來構(gòu)建一顆B+樹,然后葉子節(jié)點(diǎn)里面存儲(chǔ)了這個(gè)表的每一行數(shù)據(jù)記錄。
- 所以基于InnoDB這樣的特性,聚集索引并不僅僅是一種索引類型,還代表著一種數(shù)據(jù)的存儲(chǔ)方式。
- 同時(shí)也意味著每個(gè)表里面必須要有一個(gè)主鍵,如果沒有主鍵,InnoDB會(huì)默認(rèn)選擇或者添加一個(gè)隱藏列作為主鍵索引來存儲(chǔ)這個(gè)表的數(shù)據(jù)行。一般情況是建議使用自增id作為主鍵,這樣的話id本身具有連續(xù)性使得對應(yīng)的數(shù)據(jù)也會(huì)按照順序存儲(chǔ)在磁盤上,寫入性能和檢索性能都很高。否則,如果使用uuid這種隨機(jī)id,那么在頻繁插入數(shù)據(jù)的時(shí)候,就會(huì)導(dǎo)致隨機(jī)磁盤IO,從而導(dǎo)致性能較低。
- 需要注意的是,InnoDB里面只能存在一個(gè)聚集索引,原因很簡單,如果存在多個(gè)聚集索引,那么意味著這個(gè)表里面的數(shù)據(jù)存在多個(gè)副本,造成磁盤空間的浪費(fèi),以及數(shù)據(jù)維護(hù)的困難。
- (如圖)由于在InnoDB里面,主鍵索引表示的是一種數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),所以如果是基于非聚集索引來查詢一條完整的記錄,最終還是需要訪問主鍵索引來檢索。
2.請你簡單說一下Mysql的事務(wù)隔離級別
事務(wù)隔離級別,是為了解決多個(gè)并行事務(wù)競爭導(dǎo)致的數(shù)據(jù)安全問題的一種規(guī)范。
具體來說,多個(gè)事務(wù)競爭可能會(huì)產(chǎn)生三種不同的現(xiàn)象。
1.(如圖)假設(shè)有兩個(gè)事務(wù)T1/T2同時(shí)在執(zhí)行,T1事務(wù)有可能會(huì)讀取到T2事務(wù)未提交的數(shù)據(jù),但是未提交的事務(wù)T2可能會(huì)回滾,也就導(dǎo)致了T1事務(wù)讀取到最終不一定存在的數(shù)據(jù)產(chǎn)生臟讀的現(xiàn)象。
2.(如圖)假設(shè)有兩個(gè)事務(wù)T1/T2同時(shí)執(zhí)行,事務(wù)T1在不同的時(shí)刻讀取同一行數(shù)據(jù)的時(shí)候結(jié)果可能不一樣,從而導(dǎo)致不可重復(fù)讀的問題。
3.(如圖),假設(shè)有兩個(gè)事務(wù)T1/T2同時(shí)執(zhí)行,事務(wù)T1執(zhí)行范圍查詢或者范圍修改的過程中,事務(wù)T2插入了一條屬于事務(wù)T1范圍內(nèi)的數(shù)據(jù)并且提交了,這時(shí)候在事務(wù)T1查詢發(fā)現(xiàn)多出來了一條數(shù)據(jù),或者在T1事務(wù)發(fā)現(xiàn)這條數(shù)據(jù)沒有被修改,看起來像是產(chǎn)生了幻覺,這種現(xiàn)象稱為幻讀。
而這三種現(xiàn)象在實(shí)際應(yīng)用中,可能有些場景不能接受某些現(xiàn)象的存在,所以在SQL標(biāo)準(zhǔn)中定義了四種隔離級別,分別是:
- 讀未提交,在這種隔離級別下,可能會(huì)產(chǎn)生臟讀、不可重復(fù)讀、幻讀。
- 讀已提交(RC),在這種隔離級別下,可能會(huì)產(chǎn)生不可重復(fù)讀和幻讀。
- 可重復(fù)讀(RR),在這種隔離級別下,可能會(huì)產(chǎn)生幻讀
- 串行化,在這種隔離級別下,多個(gè)并行事務(wù)串行化執(zhí)行,不會(huì)產(chǎn)生安全性問題。
這四種隔離級別里面,只有串行化解決了全部的問題,但也意味著這種隔離級別的性能是最低的。
3.MVCC的理解
對于MVCC的理解,我覺得可以先從數(shù)據(jù)庫的三種并發(fā)場景說起:
第一種:讀讀
就是線程A與線程B同時(shí)在進(jìn)行讀操作,這種情況下不會(huì)出現(xiàn)任何并發(fā)問題。
第二種:讀寫
就是線程A與線程B在同一時(shí)刻分別進(jìn)行讀和寫操作。
這種情況下,可能會(huì)對數(shù)據(jù)庫中的數(shù)據(jù)造成以下問題:
- 事物隔離性問題,
- 出現(xiàn)臟讀,幻讀,不可重復(fù)讀的問題
第三種:寫寫
就是線程A與線程B同時(shí)進(jìn)行寫操作
這種情況下可能會(huì)存在數(shù)據(jù)更新丟失的問題。
而MVCC就是為了解決事務(wù)操作中并發(fā)安全性問題的無鎖并發(fā)控制技術(shù)全稱為Multi-Version Concurrency Control ,也就是多版本并發(fā)控制。它是通過數(shù)據(jù)庫記錄中的隱式字段,undo日志 ,Read View 來實(shí)現(xiàn)的。
MVCC主要解決了三個(gè)問題
- 第一個(gè)是:通過MVCC 可以解決讀寫并發(fā)阻塞問題從而提升數(shù)據(jù)并發(fā)處理能力
- 第二個(gè)是:MVCC 采用了樂觀鎖的方式實(shí)現(xiàn),降低了死鎖的概率
- 第三個(gè)是:解決了一致性讀的問題也就是事務(wù)啟動(dòng)時(shí)根據(jù)某個(gè)條件讀取到的數(shù)據(jù),直到事務(wù)結(jié)束時(shí),再次執(zhí)行相同條件,還是讀到同一份數(shù)據(jù),不會(huì)發(fā)生變化。
而我們在使用MVCC時(shí)一般會(huì)根據(jù)業(yè)務(wù)場景來選擇組合搭配樂觀鎖或悲觀鎖。
這兩個(gè)組合中,MVCC用來解決讀寫沖突,樂觀鎖或者悲觀鎖解決寫寫沖突從而最大程度的提高數(shù)據(jù)庫并發(fā)性能。
4.日常工作中是怎么優(yōu)化SQL
- 加索引,增加索引是一種簡單高效的手段,但是需要選擇合適的列,同時(shí)避免導(dǎo)致索引失效的操作,比如like、函數(shù)等。
- 避免返回不必要的數(shù)據(jù)列,減少返回的數(shù)據(jù)列可以增加查詢的效率。
- 根據(jù)查詢分析器適當(dāng)優(yōu)化SQL的結(jié)構(gòu),比如是否走全表掃描、避免子查詢等
- 分庫分表,在單表數(shù)據(jù)量較大或者并發(fā)連接數(shù)過高的情況下,通過這種方式可以有效提升查詢效率
- 讀寫分離,針對讀多寫少的場景,這樣可以保證寫操作的數(shù)據(jù)庫承受更小的壓力,也可以緩解獨(dú)占鎖和共享鎖的競爭。
5.Mysql為什么使用B+Tree作為索引結(jié)構(gòu)
首先,常規(guī)的數(shù)據(jù)庫存儲(chǔ)引擎,一般都是采用B樹或者B+樹來實(shí)現(xiàn)索引的存儲(chǔ)。
(如圖)因?yàn)锽樹是一種多路平衡樹,用這種存儲(chǔ)結(jié)構(gòu)來存儲(chǔ)大量數(shù)據(jù),它的整個(gè)高度會(huì)相比二叉樹來說,會(huì)矮很多。
而對于數(shù)據(jù)庫來說,所有的數(shù)據(jù)必然都是存儲(chǔ)在磁盤上的,而磁盤IO的效率實(shí)際上是很低的,特別是在隨機(jī)磁盤IO的情況下效率更低。
所以樹的高度能夠決定磁盤IO的次數(shù),磁盤IO次數(shù)越少,對于性能的提升就越大,這也是為什么采用B樹作為索引存儲(chǔ)結(jié)構(gòu)的原因。
(如圖)但是在Mysql的InnoDB存儲(chǔ)引擎里面,它用了一種增強(qiáng)的B樹結(jié)構(gòu),也就是B+樹來作為索引和數(shù)據(jù)的存儲(chǔ)結(jié)構(gòu)。
相比較于B樹結(jié)構(gòu),B+樹做了幾個(gè)方面的優(yōu)化。
- B+樹的所有數(shù)據(jù)都存儲(chǔ)在葉子節(jié)點(diǎn),非葉子節(jié)點(diǎn)只存儲(chǔ)索引。
- 葉子節(jié)點(diǎn)中的數(shù)據(jù)使用雙向鏈表的方式進(jìn)行關(guān)聯(lián)。
使用B+樹來實(shí)現(xiàn)索引的原因,我認(rèn)為有幾個(gè)方面。
- B+樹非葉子節(jié)點(diǎn)不存儲(chǔ)數(shù)據(jù),所以每一層能夠存儲(chǔ)的索引數(shù)量會(huì)增加,意味著B+樹在層高相同的情況下存儲(chǔ)的數(shù)據(jù)量要比B樹要多,使得磁盤IO次數(shù)更少。
- 在Mysql里面,范圍查詢是一個(gè)比較常用的操作,而B+樹的所有存儲(chǔ)在葉子節(jié)點(diǎn)的數(shù)據(jù)使用了雙向鏈表來關(guān)聯(lián),所以在查詢的時(shí)候只需查兩個(gè)節(jié)點(diǎn)進(jìn)行遍歷就行,而B樹需要獲取所有節(jié)點(diǎn),所以B+樹在范圍查詢上效率更高。
- 在數(shù)據(jù)檢索方面,由于所有的數(shù)據(jù)都存儲(chǔ)在葉子節(jié)點(diǎn),所以B+樹的IO次數(shù)會(huì)更加穩(wěn)定一些。
- 因?yàn)槿~子節(jié)點(diǎn)存儲(chǔ)所有數(shù)據(jù),所以B+樹的全局掃描能力更強(qiáng)一些,因?yàn)樗恍枰獟呙枞~子節(jié)點(diǎn)。但是B樹需要遍歷整個(gè)樹。
另外,基于B+樹這樣一種結(jié)構(gòu),如果采用自增的整型數(shù)據(jù)作為主鍵,還能更好的避免增加數(shù)據(jù)的時(shí)候,帶來葉子節(jié)點(diǎn)分裂導(dǎo)致的大量運(yùn)算的問題。
總結(jié):
技術(shù)方案的選型,更多的是去解決當(dāng)前場景下的特定問題,并不一定是說B+樹就是最好的選擇,就像MongoDB里面采用B樹結(jié)構(gòu),本質(zhì)上來說,其實(shí)是關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫的差異。
6.Mysql索引的優(yōu)點(diǎn)和缺點(diǎn)?
索引,是一種能夠幫助Mysql高效從磁盤上檢索數(shù)據(jù)的一種數(shù)據(jù)結(jié)構(gòu)。
在Mysql中的InnoDB引擎中,采用了B+樹的結(jié)構(gòu)來實(shí)現(xiàn)索引和數(shù)據(jù)的存儲(chǔ)
Mysql里面的索引的優(yōu)點(diǎn)有很多
- 通過B+樹的結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù),可以大大減少數(shù)據(jù)檢索時(shí)的磁盤IO次數(shù),從而提升數(shù)據(jù)查詢的性能
- B+樹索引在進(jìn)行范圍查找的時(shí)候,只需要找到起始節(jié)點(diǎn),然后基于葉子節(jié)點(diǎn)的鏈表結(jié)構(gòu)往下讀取即可,查詢效率較高。
- 通過唯一索引約束,可以保證數(shù)據(jù)表中每一行數(shù)據(jù)的唯一性
當(dāng)然,索引的不合理使用,也會(huì)有帶來很多的缺點(diǎn)。
- 數(shù)據(jù)的增加、修改、刪除,需要涉及到索引的維護(hù),當(dāng)數(shù)據(jù)量較大的情況下,索引的維護(hù)會(huì)帶來較大的性能開銷。
- 一個(gè)表中允許存在一個(gè)聚簇索引和多個(gè)非聚簇索引,但是索引數(shù)不能創(chuàng)建太多,否則造成的索引維護(hù)成本過高。
- 創(chuàng)建索引的時(shí)候,需要考慮到索引字段值的分散性,如果字段的重復(fù)數(shù)據(jù)過多,創(chuàng)建索引反而會(huì)帶來性能降低。
7.索引什么時(shí)候失效?
1.在索引列上做運(yùn)算,比如使用函數(shù),Mysql在生成執(zhí)行計(jì)劃的時(shí)候,它是根據(jù)統(tǒng)計(jì)信息來判斷是否要使用索引的。
而在索引列上加函數(shù)運(yùn)算,導(dǎo)致Mysql無法識(shí)別索引列,也就不會(huì)再走索引了。
不過從Mysql8開始,增加了函數(shù)索引可以解決這個(gè)問題。
2.在一個(gè)由多列構(gòu)成的組合索引中,需要按照最左匹配法則,也就是從索引的最左列開始順序檢索,否則不會(huì)走索引。
在組合索引中,索引的存儲(chǔ)結(jié)構(gòu)是按照索引列的順序來存儲(chǔ)的,因此在sql中也需要按照這個(gè)順序才能進(jìn)行逐一匹配。
否則InnoDB無法識(shí)別索引導(dǎo)致索引失效。
3.當(dāng)索引列存在隱式轉(zhuǎn)化的時(shí)候, 比如索引列是字符串類型,但是在sql查詢中沒有使用引號(hào)。
那么Mysql會(huì)自動(dòng)進(jìn)行類型轉(zhuǎn)化,從而導(dǎo)致索引失效
4.在索引列使用不等于號(hào)、not查詢的時(shí)候,由于索引數(shù)據(jù)的檢索效率非常低,因此Mysql引擎會(huì)判斷不走索引。
5.使用like通配符匹配后綴%xxx的時(shí)候,由于這種方式不符合索引的最左匹配原則,所以也不會(huì)走索引。
但是反過來,如果通配符匹配的是前綴xxx%,符合最左匹配,也會(huì)走索引。
6.使用or連接查詢的時(shí)候,or語句前后沒有同時(shí)使用索引,那么索引會(huì)失效。只有or左右查詢字段都是索引列的時(shí)候,才會(huì)生效。
除了這些場景以外,對于多表連接查詢的場景中,連接順序也會(huì)影響索引的使用。
不過最終是否走索引,我們可以使用explain命令來查看sql的執(zhí)行計(jì)劃,然后針對性的進(jìn)行調(diào)優(yōu)即可。
8. InnoDB 與MyISAM 有什么區(qū)別
- 事務(wù)支持不同,InnoDB 支持事務(wù)處理,而 MyISAM 不支持。
- 并發(fā)處理不同:InnoDB 支持行級鎖,而 MyISAM 支持表級鎖
- 外鍵支持不同:InnoDB 支持外鍵約束,而 MyISAM 不支持
- 性能上存在差異:MyISAM 的讀取速度比 InnoDB 快,但是在高并發(fā)環(huán)境下,InnoDB 的性能更好。這是因?yàn)?InnoDB 支持行級鎖和事務(wù)處理,而 MyISAM 不支持。
所以,如果是讀多寫少的情況下,使用MyISAM引擎會(huì)更合適
5.數(shù)據(jù)安全不同:InnoDB 支持崩潰恢復(fù)和數(shù)據(jù)恢復(fù),而 MyISAM 不支持。如果 MySQL 崩潰了或者發(fā)生意外故障,InnoDB 可以通過恢復(fù)日志來恢復(fù)數(shù)據(jù)。
9.為什么 SQL 語句不要過多的 join?
- 性能問題:每個(gè) join 操作都需要對兩個(gè)或多個(gè)表進(jìn)行連接操作,這個(gè)操作需要消耗大量的計(jì)算資源和時(shí)間,如果 join 操作過多,會(huì)導(dǎo)致 SQL 的執(zhí)行效率降低,從而影響整個(gè)系統(tǒng)的性能。
- 可讀性和維護(hù)性問題:join 操作會(huì)使 SQL 語句變得復(fù)雜,難以理解和維護(hù),特別是當(dāng) join 操作涉及到多個(gè)表的時(shí)候,SQL 語句的復(fù)雜度會(huì)呈現(xiàn)指數(shù)級增長,給代碼的可讀性和可維護(hù)性帶來挑戰(zhàn)。
10.binlog和redolog有什么區(qū)別?
binlog和redolog都是Mysql里面用來記錄數(shù)據(jù)庫數(shù)據(jù)變更操作的日志。
{如圖}其中binlog主要用來做數(shù)據(jù)備份、數(shù)據(jù)恢復(fù)和數(shù)據(jù)同步,大家初步接觸這個(gè)概念 ,應(yīng)該是在Mysql的主從數(shù)據(jù)同步的場景中,master節(jié)點(diǎn)的數(shù)據(jù)變更,會(huì)寫入到binlog中,然后再把binlog中的數(shù)據(jù)通過網(wǎng)絡(luò)傳輸給slave節(jié)點(diǎn),實(shí)現(xiàn)數(shù)據(jù)同步。
問題答案
binlog和redolog的區(qū)別有很多,我可以簡單總結(jié)三個(gè)點(diǎn)
- 使用場景不同,binlog主要用來做數(shù)據(jù)備份、數(shù)據(jù)恢復(fù)、以及主從集群的數(shù)據(jù)同步; Redo Log主要用來實(shí)現(xiàn)Mysql數(shù)據(jù)庫的事務(wù)恢復(fù),保證事務(wù)的ACID特性。當(dāng)數(shù)據(jù)庫出現(xiàn)崩潰的時(shí)候,Redo Log可以把未提交的事務(wù)回滾,把已提交的事務(wù)進(jìn)行持久化,從而保證數(shù)據(jù)的一致性和持久性。
- 記錄的信息不同,binlog是記錄數(shù)據(jù)庫的邏輯變化,它提供了三種日志格式分別是statement,row以及mixed;
redo log記錄的是物理變化,也就是數(shù)據(jù)頁的變化結(jié)果。
- 記錄的時(shí)機(jī)不同, binlog是在執(zhí)行SQL語句的時(shí)候,在主線程中生成邏輯變化寫入到磁盤中,所以它是語句級別的記錄方式; RedoLog是在InnoDB存儲(chǔ)引擎層面的操作,它是在Mysql后臺(tái)線程中生成并寫入到磁盤中的,所以它是事務(wù)級別的記錄方式,一個(gè)事務(wù)操作完成以后才會(huì)被寫入到redo log中。
總結(jié)
到此這篇關(guān)于MySQL最常問的十道面試題的文章就介紹到這了,更多相關(guān)MySQL最常問面試題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql中刪除數(shù)據(jù)的四種方法小結(jié)
在MySQL數(shù)據(jù)庫中,刪除數(shù)據(jù)是一個(gè)常見的操作,它允許從表中移除不再需要的數(shù)據(jù),本文就來介紹一下四種方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10mysql中varchar類型的日期進(jìn)行比較、排序等操作的實(shí)現(xiàn)
在mysql使用過程中,日期一般都是以datetime、timestamp等格式進(jìn)行存儲(chǔ)的,但有時(shí)會(huì)因?yàn)樘厥獾男枨蠡驓v史原因,日期的存儲(chǔ)格式是varchar,那么應(yīng)該怎么進(jìn)行比較和排序等問題,本文就來介紹一下2021-11-11