Mysql常見面試題
整理一些在網上看到的零零碎碎的面試題
mysql使用的是哪種存儲引擎
MySQL支持很多種存儲引擎,MySQL5.5版本之前默認使用的是MyISAM存儲引擎,從MySQL5.5版本之后,MySQL的默認內置存儲引擎就是InnoDB了
MyISAM和InnoDB有什么區別
- InnoDB支持事務,MyISAM不支持
- InnoDB支持外鍵,MyISAM不支持
- 查詢總記錄數(select count(*))時,InnoDB效率更低,因為InnoDB需要去統計行數,而MyISAM將行數單獨存儲了
- InnoDB災難恢復性比MyISAM好
- InnoDB最小鎖粒度為行級鎖,可以支持更高的並發;MyISAM最小鎖粒度為表級鎖,並發度很差,加鎖快,鎖沖突較少,不太容易發生死鎖
- InnoDB 是聚集索引,MyISAM 是非聚集索引。聚集索引的文件存放在主鍵索引的葉子節點上,因此 InnoDB 必須要有主鍵,通過主鍵索引效率很高。非聚集索引,數據文件是分離的,索引保存的是數據文件的指針
MyISAM和InnoDB如何選擇
1、是否要支持事務,如果要請選擇 InnoDB,如果不需要可以考慮 MyISAM
2、如果表中絕大多數都只是讀查詢,可以考慮 MyISAM,如果既有讀寫也挺頻繁,就用InnoDB
3、系統奔潰后,MyISAM恢復起來更困難,能否接受,不能接受就選 InnoDB
4、MySQL5.5版本開始Innodb已經成為Mysql的默認引擎(之前是MyISAM),說明其優勢是有目共睹的。如果你不知道用什么存儲引擎,那就用InnoDB,至少不會差
什么是聚集索引和非聚集索引
聚集索引的索引順序與表數據存儲順序一致,葉子節點存儲的是真實的數據
非聚集索引的索引順序與表數據存儲順序無關,葉子節點存儲的是指向真實數據的指針(主鍵的值)
當查詢使用聚集索引時,在對應的葉子節點,可以獲取到整行數據,不用再次進行回表查詢
非聚集索引一定會回表查詢嗎
不一定,這涉及到查詢語句所要求的字段是否全部命中了索引(覆蓋索引),如果全部命中了索引,那么就不必再進行回表查詢,eg:
select id,name from user where name='shenjian'; # 創建了name索引,能夠命中name索引,索引葉子節點存儲了主鍵id,通過name的索引樹即可獲取id和name,無需回表,符合索引覆蓋,效率較高
MySQL 5.6中,對索引做了哪些優化
Index Condition Pushdown(索引下推)優化,eg:
people表中(zipcode,lastname,firstname)構成一個索引
SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%etrunia%' AND address LIKE '%Main Street%';
如果沒有使用索引下推技術,則MySQL會通過zipcode='95054'從存儲引擎中查詢對應的數據,返回到MySQL服務端,然后MySQL服務端基於lastname LIKE '%etrunia%'和address LIKE '%Main Street%'來判斷數據是否符合條件
如果使用了索引下推技術,則MYSQL首先會返回符合zipcode='95054'的索引,然后根據lastname LIKE '%etrunia%'和address LIKE '%Main Street%'來判斷索引是否符合條件。如果符合條件,則根據該索引來定位對應的數據,如果不符合,則直接篩掉。有了索引下推優化,可以在有like條件查詢的情況下,減少回表次數
MySQL常用存儲引擎的底層原理
InnoDB和MyISAM這兩種引擎底層都是采用B+樹的數據結構來構建索引
B樹是一棵多路平衡查找樹,簡單來說,B樹可以看做平衡二叉樹的進階版,它與平衡二叉樹的不同點主要在B樹的一個節點可以存放多個關鍵字,並且B樹的每個節點可以有兩個以上的子節點,而這些都取決於B樹的階數,當B樹的階數為2時,它就是一個普通的平衡二叉樹
B+樹是B樹的變種,在B+樹中,所有的關鍵字都會保存在葉子節點中,葉子節點之間也會有指針進行連接,形成一個鏈表的形式,和B樹相比,這樣的結構方便范圍查找。比如要查詢大於3的關鍵字,我們從根節點往下遍歷,找到關鍵字為3的葉子節點之后,直接讀取3之后的葉子節點就可以了,而不用一次次的從根節點去遍歷大於3的關鍵字。當我們進行的范圍查找進行倒序操作的時候,憑借葉子節點的單向鏈表是無法實現的,因此MySQL中的B+樹結構做了一些調整,MySQL將B+樹葉子節點的單向鏈表改為雙向鏈表
Hash索引和B+樹索引有什么區別
- hash索引底層就是hash表,B+樹底層實現是多路平衡查找樹
- 一般情況下hash索引進行等值查詢更快,調用一次hash函數就可以獲取到相應的鍵值,但是無法進行范圍查詢。因為在hash索引中經過hash函數建立索引之后,索引的順序與原順序無法保持-致,不能支持范圍查詢。而B+樹的的所有節點皆遵循(左節點小於父節點,右節點大於父節點,天然支持范圍
- hash索引不支持使用索引進行排序,原理同上
什么時候索引會失效
- 違反最左前綴法則
- 對索引列進行運算(計算、函數、(自動or手動)類型轉換)
- 索引列的使用在范圍條件之后
- 索引列使用不等於(!=或者<>)
- is null或is not null有可能導致索引失效
- like以通配符開頭(可以使用覆蓋索引解決此索引失效)
- 字符串類型不加單引號(mysql會隱式轉換成字符串,導致對索引列進行了運算)
- or語句前后沒有同時使用索引。當or左右查詢字段只有一個是索引,該索引失效,只有當or左右查詢字段均為索引時,才會生效
事務的特性
- 原子性(Atomicity)
原子性是指事務包含的所有操作要么全部成功,要么全部失敗回滾,因此事務的操作如果成功就必須要完全應用到數據庫,如果操作失敗則不能對數據庫有任何影響。
- 一致性(Consistency)
一致性是指事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之后都必須處於一致性狀態。舉例來說,假設用戶A和用戶B兩者的錢加起來一共是1000,那么不管A和B之間如何轉賬、轉幾次賬,事務結束后兩個用戶的錢相加起來應該還得是1000,這就是事務的一致性。
- 隔離性(Isolation)
隔離性是指並發的事務是相互隔離的,一個事務的執行不能被其他事務干擾
- 持久性(Durability)
持久性是指一個事務一旦被提交了,那么對數據庫中的數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作。
MySQL同時有多個事務可能會產生什么問題
- 臟讀:A事務讀取到了B事務未提交的內容,而B事務后面進行了回滾.
- 不可重復讀:B事務讀取了兩次數據,在這兩次的讀取過程中A事務修改了數據,B事務的這兩次讀取出來的數據不一樣
- 幻讀:B事務讀取了兩次數據,在這兩次的讀取過程中A事務添加了數據,B事務的這兩次讀取出來的集合不一樣,看起來和不可重復讀差不多,幻讀強調的集合的增減,而不是單獨一條數據的修改
說說MySQL事務隔離級別
- 讀未提交(Read Uncommitted)
在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別是最低的隔離級別,雖然擁有超高的並發處理能力及很低的系統開銷,但很少用於實際應用。因為采用這種隔離級別只能防止更新丟失問題,不能解決臟讀,不可重復讀及幻讀問題。
- 讀已提交(Read Committed)
這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別可以防止臟讀問題,但會出現不可重復讀及幻讀問題。
- 可重復讀(Repeatable Read)
這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在並發讀取數據時,會看到同樣的數據行。這種隔離級別可以防止除幻讀外的其他問題
- 可串行化(Serializable)
這是最高的隔離級別,它通過強制事務排序,使之不可能相互沖突,從而解決幻讀、第二類更新丟失問題。在這個級別,可以解決上面提到的所有並發問題,但可能導致大量的超時現象和鎖競爭,通常數據庫不會用這個隔離級別,我們需要其他的機制來解決這些問題:樂觀鎖和悲觀鎖。
四種隔離級別會產生的問題如下圖

