整理了一些 MySQL的面試題
索引相關
1. 什麼是索引?常見的索引有哪些?
索引是一種數據結構,可以幫助我們快速的進行數據的查找.
普通索引 唯一索引 主鍵索引 組合索引 全文索引 空間索引
2. 索引是個什麼樣的數據結構呢?
索引的數據結構和具體存儲引擎的實現有關, 在MySQL中使用較多的索引有Hash索引,B+樹索引等,而我們經常使用的InnoDB存儲引擎的默認索引實現爲:B+樹索引.
3. Hash索引和B+樹所有有什麼區別或者說優劣呢?
Hash索引和B+樹索引的底層實現原理:
hash索引底層就是hash表,進行查找時,調用一次hash函數就可以獲取到相應的鍵值,之後進行回表查詢獲得實際數據.B+樹底層實現是多路平衡查找樹.對於每一次的查詢都是從根節點出發,查找到葉子節點方可以獲得所查鍵值,然後根據查詢判斷是否需要回表查詢數據.
Hash索引與B+樹的不同:
hash索引進行等值查詢更快(一般情況下),但是卻無法進行範圍查詢.因爲在hash索引中經過hash函數建立索引之後,索引的順序與原順序無法保持一致,不能支持範圍查詢
B+樹的的所有節點皆遵循(左節點小於父節點,右節點大於父節點,多叉樹也類似),天然支持範圍.
hash索引不支持使用索引進行排序,hash索引不支持模糊查詢以及多列索引的最左前綴匹配.原理也是因爲hash函數的不可預測.AAAA和AAAAB的索引沒有相關性.Hash索引任何時候都避免不了回表查詢數據
B+樹在符合某些條件(聚簇索引,覆蓋索引等)的時候可以只通過索引完成查詢.
hash索引雖然在等值查詢上較快,但是不穩定.性能不可預測,當某個鍵值存在大量重複的時候,發生hash碰撞,此時效率可能極差.
B+樹的查詢效率比較穩定,對於所有的查詢都是從根節點到葉子節點,且樹的高度較低
4. B+樹在滿足聚簇索引和覆蓋索引的時候不需要回表查詢數據,什麼是聚簇索引?
在B+樹的索引中,葉子節點可能存儲了當前的key值,也可能存儲了當前的key值以及整行的數據,這就是聚簇索引和非聚簇索引. 在InnoDB中,只有主鍵索引是聚簇索引,如果沒有主鍵,則挑選一個唯一鍵建立聚簇索引.如果沒有唯一鍵,則隱式的生成一個鍵來建立聚簇索引.當查詢使用聚簇索引時,在對應的葉子節點,可以獲取到整行數據,因此不用再次進行回表查詢
5. 非聚簇索引一定會回表查詢嗎?
不一定,這涉及到查詢語句所要求的字段是否全部命中了索引,如果全部命中了索引,那麼就不必再進行回表查詢
6. 在建立索引的時候,都有哪些需要考慮的因素呢?
建立索引的時候一般要考慮到字段的使用頻率,經常作爲條件進行查詢的字段比較適合.如果需要建立聯合索引的話,還需要考慮聯合索引中的順序.此外也要考慮其他方面,比如防止過多的所有對錶造成太大的壓力.這些都和實際的表結構以及查詢方式有關
7. 創建的索引有沒有被使用到?或者說怎麼纔可以知道這條語句運行很慢的原因?
MySQL提供了explain命令來查看語句的執行計劃,MySQL在執行某個語句之前,會將該語句過一遍查詢優化器,之後會拿到對語句的分析,也就是執行計劃,其中包含了許多信息. 可以通過其中和索引有關的信息來分析是否命中了索引,例如possilbe_key,key,key_len等字段,分別說明了此語句可能會使用的索引,實際使用的索引以及使用的索引長度.
8. 那麼在哪些情況下會發生針對該列創建了索引但是在查詢的時候並沒有使用呢?
- 使用不等於查詢,
- 列參與了數學運算或者函數
- 在字符串like時左邊是通配符.類似於’%aaa’
- 當mysql分析全表掃描比使用索引快的時候不使用索引
- 當使用聯合索引,前面一個條件爲範圍查詢,後面的即使符合最左前綴原則,也無法使用索引
9. MySQL中索引的優點和缺點和使用原則
優點:
1、所有的MySql列類型(字段類型)都可以被索引,也就是可以給任意字段設置索引
2、大大加快數據的查詢速度
缺點:
1、創建索引和維護索引要耗費時間,並且隨着數據量的增加所耗費的時間也會增加
2、索引也需要佔空間,我們知道數據表中的數據也會有最大上線設置的,如果我們有大量的索引,索引文件可能會比數據文件更快達到上線值
3、當對錶中的數據進行增加、刪除、修改時,索引也需要動態的維護,降低了數據的維護速度。
事務相關
1. ACID是什麼?可以詳細說一下嗎?
A=Atomicity 原子性,就是上面說的,要麼全部成功,要麼全部失敗.不可能只執行一部分操作.
C=Consistency 系統(數據庫)總是從一個一致性的狀態轉移到另一個一致性的狀態,不會存在中間狀態.
I=Isolation 隔離性: 通常來說:一個事務在完全提交之前,對其他事務是不可見的.注意前面的通常來說加了紅色,意味着有例外情況.
D=Durability 持久性,一旦事務提交,那麼就永遠是這樣子了,哪怕系統崩潰也不會影響到這個事務的結果.
2.同時有多個事務在進行會怎麼樣呢?
多事務的併發進行一般會造成以下幾個問題:
- 髒讀: A事務讀取到了B事務未提交的內容,而B事務後面進行了回滾.
- 不可重複讀: 當設置A事務只能讀取B事務已經提交的部分,會造成在A事務內的兩次查詢,結果竟然不一樣,因爲在此期間B事務進行了提交操作.
- 幻讀: A事務讀取了一個範圍的內容,而同時B事務在此期間插入了一條數據.造成"幻覺".
3.MySQL的事務隔離級別瞭解嗎?
MySQL的四種隔離級別如下:
- 未提交讀(READ UNCOMMITTED)
這就是上面所說的例外情況了,這個隔離級別下,其他事務可以看到本事務沒有提交的部分修改.因此會造成髒讀的問題(讀取到了其他事務未提交的部分,而之後該事務進行了回滾).
這個級別的性能沒有足夠大的優勢,但是又有很多的問題,因此很少使用.
- 已提交讀(READ COMMITTED)
其他事務只能讀取到本事務已經提交的部分.這個隔離級別有 不可重複讀的問題,在同一個事務內的兩次讀取,拿到的結果竟然不一樣,因爲另外一個事務對數據進行了修改.
- REPEATABLE READ(可重複讀)
可重複讀隔離級別解決了上面不可重複讀的問題(看名字也知道),但是仍然有一個新問題,就是 幻讀,當你讀取id> 10 的數據行時,對涉及到的所有行加上了讀鎖,此時例外一個事務新插入了一條id=11的數據,因爲是新插入的,所以不會觸發上面的鎖的排斥,那麼進行本事務進行下一次的查詢時會發現有一條id=11的數據,而上次的查詢操作並沒有獲取到,再進行插入就會有主鍵衝突的問題.
- SERIALIZABLE(可串行化)
這是最高的隔離級別,可以解決上面提到的所有問題,因爲他強制將所以的操作串行執行,這會導致併發性能極速下降,因此也不是很常用.
4 Innodb使用的是哪種隔離級別呢?
InnoDB默認使用的是可重複讀隔離級別.
鎖相關
1. MySQL的鎖瞭解嗎?
當數據庫有併發事務的時候,可能會產生數據的不一致,這時候需要一些機制來保證訪問的次序,鎖機制就是這樣的一個機制.就像酒店的房間,如果大家隨意進出,就會出現多人搶奪同一個房間的情況,而在房間上裝上鎖,申請到鑰匙的人才可以入住並且將房間鎖起來,其他人只有等他使用完畢纔可以再次使用.
2.MySQL都有哪些鎖呢?像上面那樣子進行鎖定豈不是有點阻礙併發效率了?
從鎖的類別上來講,有共享鎖和排他鎖.
共享鎖: 又叫做讀鎖. 當用戶要進行數據的讀取時,對數據加上共享鎖.共享鎖可以同時加上多個.
排他鎖: 又叫做寫鎖. 當用戶要進行數據的寫入時,對數據加上排他鎖.排他鎖只可以加一個,他和其他的排他鎖,共享鎖都相斥.
用上面的例子來說就是用戶的行爲有兩種,一種是來看房,多個用戶一起看房是可以接受的. 一種是真正的入住一晚,在這期間,無論是想入住的還是想看房的都不可以.
鎖的粒度取決於具體的存儲引擎,InnoDB實現了行級鎖,頁級鎖,表級鎖.他們的加鎖開銷從大大小,併發能力也是從大到小.
3.什麼是樂觀鎖?什麼是悲觀鎖?
悲觀鎖(Pessimistic Lock)
當我們要對一個數據庫中的一條數據進行修改的時候,爲了避免同時被其他人修改,最好的辦法就是直接對該數據進行加鎖以防止併發。這種藉助數據庫鎖機制,在修改數據之前先鎖定,再修改的方式被稱之爲悲觀併發控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)。
悲觀鎖主要是共享鎖或排他鎖
- 共享鎖又稱爲讀鎖,簡稱S鎖。顧名思義,共享鎖就是多個事務對於同一數據可以共享一把鎖,都能訪問到數據,但是隻能讀不能修改。
- 排他鎖又稱爲寫鎖,簡稱X鎖。顧名思義,排他鎖就是不能與其他鎖並存,如果一個事務獲取了一個數據行的排他鎖,其他事務就不能再獲取該行的其他鎖,包括共享鎖和排他鎖,但是獲取排他鎖的事務是可以對數據行讀取和修改。
- 悲觀併發控制實際上是“先取鎖再訪問”的保守策略,爲數據處理的安全提供了保證。
- 但是在效率方面,處理加鎖的機制會讓數據庫產生額外的開銷,還有增加產生死鎖的機會。另外還會降低並行性,一個事務如果鎖定了某行數據,其他事務就必須等待該事務處理完纔可以處理那行數據。
樂觀鎖( Optimistic Locking )
樂觀鎖是相對悲觀鎖而言的,樂觀鎖假設數據一般情況下不會造成衝突,所以在數據進行提交更新的時候,纔會正式對數據的衝突與否進行檢測,如果發現衝突了,則返回給用戶錯誤的信息,讓用戶決定如何去做。
樂觀併發控制相信事務之間的數據競爭(data race)的概率是比較小的,因此儘可能直接做下去,直到提交的時候纔去鎖定,所以不會產生任何鎖和死鎖。
在樂觀鎖與悲觀鎖的選擇上面,主要看下兩者的區別以及適用場景就可以了。
- 樂觀鎖並未真正加鎖,效率高。一旦鎖的粒度掌握不好,更新失敗的概率就會比較高,容易發生業務失敗。
- 悲觀鎖依賴數據庫鎖,效率低。更新失敗的概率比較低。
存儲引擎相關
1. MySQL支持哪些存儲引擎?
MySQL支持多種存儲引擎,比如InnoDB,MyISAM,Memory,Archive等等.在大多數的情況下,直接選擇使用InnoDB引擎都是最合適的,InnoDB也是MySQL的默認存儲引擎.
- InnoDB和MyISAM有什麼區別?
- InnoDB支持事物,而MyISAM不支持事物
- InnoDB支持行級鎖,而MyISAM支持表級鎖
- InnoDB支持MVCC, 而MyISAM不支持
- InnoDB支持外鍵,而MyISAM不支持
- InnoDB不支持全文索引,而MyISAM支持。
2. 什麼是存儲過程?有哪些優缺點?
存儲過程是一些預編譯的SQL語句。1、更加直白的理解:存儲過程可以說是一個記錄集,它是由一些T-SQL語句組成的代碼塊,這些T-SQL語句代碼像一個方法一樣實現一些功能(對單表或多表的增刪改查),然後再給這個代碼塊取一個名字,在用到這個功能的時候調用他就行了。2、存儲過程是一個預編譯的代碼塊,執行效率比較高,一個存儲過程替代大量T_SQL語句 ,可以降低網絡通信量,提高通信速率,可以一定程度上確保數據安全
3.關心過業務系統裏面的sql耗時嗎?統計過慢查詢嗎?對慢查詢都怎麼優化過?
慢查詢的優化首先要搞明白慢的原因是什麼? 是查詢條件沒有命中索引?是load了不需要的數據列?還是數據量太大?
所以優化也是針對這三個方向來的,
- 首先分析語句,看看是否load了額外的數據,可能是查詢了多餘的行並且拋棄掉了,可能是加載了許多結果中並不需要的列,對語句進行分析以及重寫.
- 分析語句的執行計劃,然後獲得其使用索引的情況,之後修改語句或者修改索引,使得語句可以儘可能的命中索引.
- 如果對語句的優化已經無法進行,可以考慮表中的數據量是否太大,如果是的話可以進行橫向或者縱向的分表
零散試題相關
1.列設置爲 AUTO INCREMENT 時,如果在表中達到最大值,會發生什麼情況?
它會停止遞增,任何進一步的插入都將產生錯誤,因爲密鑰已被使用。
2.一張表,裏面有 ID 自增主鍵,當 insert 了 17 條記錄之後,刪除了第 15,16,17 條記錄, 再把 Mysql 重啓,再 insert 一條記錄,這條記錄的 ID 是 18 還是 15 ?
如果表的類型是 MyISAM,那麼是 18。因爲 MyISAM 表會把自增主鍵的最大 ID 記錄到數據文件裏,重啓 MySQL 自增主鍵的最大ID 也不會丟失。
如果表的類型是 InnoDB,那麼是 15。InnoDB 表只是把自增主鍵的最大 ID 記錄到內存中,所以重啓數據庫或者是對錶進行OPTIMIZE 操作,都會導致最大 ID 丟失。
3.數據庫三範式是什麼?
第一範式(1NF):字段具有原子性,不可再分。(所有關係型數據庫系 統都滿足第一範式數據庫表中的字段都是單一屬性的,不可再分)
第二範式(2NF)是在第一範式(1NF)的基礎上建立起來的,即滿足 第二範式(2NF)必須先滿足第一範式(1NF)。要求數據庫表中的每 個實例或行必須可以被惟一地區分。通常需要爲表加上一個列,以存儲 各個實例的惟一標識。這個惟一屬性列被稱爲主關鍵字或主鍵。
滿足第三範式(3NF)必須先滿足第二範式(2NF)。簡而言之,第三 範式(3NF)要求一個數據庫表中不包含已在其它表中已包含的非主關 鍵字信息。>所以第三範式具有如下特徵: >>1. 每一列只有一個 值 >>2. 每一行都能區分。>>3. 每一個表都不包含其他表已經包含 的非主關鍵字信息。
4.mysql 的複製原理以及流程?
Mysql 內建的複製功能是構建大型,高性能應用程序的基礎。將 Mysql 的數據 分佈到多個系統上去,這種分佈的機制,是通過將 Mysql 的某一臺主機的數據 複製到其它主機(slaves)上,並重新執行一遍來實現的。* 複製過程中一 個服務器充當主服務器,而一個或多個其它服務器充當從服務器。主服務器將 更新寫入二進制日誌文件,並維護文件的一個索引以跟蹤日誌循環。這些日誌 可以記錄發送到從服務器的更新。當一個從服務器連接主服務器時,它通知主 服務器在日誌中讀取的最後一次成功更新的位置。從服務器接收從那時起發生 的任何更新,然後封鎖並等待主服務器通知新的更新。
過程如下 :
主服務器 把更新記錄到二進制日誌文件中。
從服務器把主服務器的二進制日誌拷貝 到自己的中繼日誌(replay log)中。
從服務器重做中繼日誌中的時間, 把更新應用到自己的數據庫上。
5.#{}和${}的區別是什麼?
{}是預編譯處理,${}是字符串替換。
Mybatis 在處理#{}時,會將 sql 中的#{}替換爲?號,調用 PreparedStatement 的 set 方法 來賦值。
Mybatis 在處理{}替換成變量的值。
使用#{}可以有效的防止 SQL 注入,提高系統安全性。
6.#{}和${}的區別是什麼?
索引的數據結構和具體存儲引擎的實現有關, 在MySQL中使用較多的索引有Hash索引,B+樹索引等。而我們經常使用的InnoDB存儲引擎的默認索引實現爲:B+樹索引。
7.一條sql執行過長的時間,你如何優化,從哪些方面?
1、查看sql是否涉及多表的聯表或者子查詢,如果有,看是否能進行業務拆分,相關字段冗餘或者合併成臨時表(業務和算法的優化)。
2、涉及鏈表的查詢,是否能進行分表查詢,單表查詢之後的結果進行字段整合。
3、如果以上兩種都不能操作,非要鏈表查詢,那麼考慮對相對應的查詢條件做索引。加快查詢速度。
4、針對數量大的表進行歷史表分離(如交易流水錶)。
5、數據庫主從分離,讀寫分離,降低讀寫針對同一表同時的壓力,至於主從同步,mysql有自帶的binlog實現 主從同步。
6、explain分析sql語句,查看執行計劃,分析索引是否用上,分析掃描行數等等
8.UNION
和 UNION ALL
有什麼區別?
UNION
用於 合併兩個或多個 SELECT
語句的結果集,並消去表中任何重複行。UNION
內部的 SELECT 語句必須擁有相同數量的列,列也必須擁有相似的數據類型。同時,每條 SELECT 語句中的列的順序必須相同。
UNION ALL
基本使用和UNION
是一致的,但是UNION ALL
不會消除表中的重複行。
9.MySQL中空值和NULL的區別?
-
空值(”)是不佔用空間的,判斷空字符用 = ” 或者 <> ” 來進行處理。
-
NULL值是未知的,且佔用空間,不走索引;判斷 NULL 用 IS NULL 或者 is not null ,SQL 語句函數中可以使用 ifnull ()函數來進行處理。
-
無法比較 NULL 和 0;它們是不等價的。
-
無法使用比較運算符來測試 NULL 值,比如 =, <, 或者 <>。
-
NULL
值可以使用<=>
符號進行比較,該符號與等號作用相似,但對NULL
有意義。 -
進行 count ()統計某列的記錄數的時候,如果採用的 NULL 值,會別系統自動忽略掉,但是空值是統計到其中。
10.mysql數據庫常見的故障有哪些?如何處理
-
SQL執行計劃改變導致SQL佔用大量CPU。
-
統計SQL在數據量增大後佔用大量磁盤IO和CPU。
-
SQL中存在NULL條件,導致執行計劃走錯。
-
存儲過程沒有使用預處理和綁定變量,導致解析SQL佔用大量SQL。
-
大批量修改操作沒有SET AUTOCOMMIT=0,導致每條SQL均提交,效率低。
-
SQL未經審覈上線,導致沒有建立索引,執行計劃爲全表掃描。
11.如何做 MySQL 的性能優化?
- 爲搜索字段創建索引。
- 避免使用 select *,列出需要查詢的字段。
- 垂直分割分表。
- 選擇正確的存儲引擎。