前言:前面介紹了Java、JVM相關方面的題目,該篇介紹數據庫方面相關的題目,這里數據庫為MySql,因為筆者或朋友在面試過程中都是涉及MySql的相關知識點。
數據庫篇
在數據庫題目中,由於現在大部分公司都是使用MySql作為數據庫,因此筆者及其朋友所遇到的問題也都是MySql相關的知識點。
1)MySql中索引的基本定義,優劣勢,以及索引優化。
索引是幫助Mysql高效獲取數據的數據結構,因此,索引的本質就是數據結構,索引的目的在於提高查詢效率,可類比字典。
索引:排好序的快速查找的數據結構。
用途:排序 + 快速查找。注意,是兩種功能。
數據庫除了存儲數據本身之外,還維護着一個滿足特定查找算法的數據結構,這些數據結構以某種方式指向數據,這樣就可以在這些數據結構的基礎上實現高級查找算法,這種數據結構就是索引。
MySql索引通常是指B+樹索引。
索引優勢:
類似書籍的目錄,提高數據檢索的效率,降低數據庫的 IO 成本(因為數據最終是存儲在磁盤上的)。
通過索引列對數據進行排序,降低數據排序的成本,降低了 CPU 的消耗(因為排好序,查詢速度增加)。
索引劣勢:
索引也是一張表,保存了主鍵與索引字段,並指向實體表的記錄,所以索引列也是要占用磁盤空間的。
雖然提高了查詢速度,但是會降低更新速度(因為數據更新后,需要重新對索引排序),如 INSERT、UPDATE、DELETE 操作。
哪些情況適合建索引:
①主鍵自動建立唯一索引。
②頻繁作為查詢條件的字段應該創建索引。
③查詢中與其它表關聯的字段,外鍵關系建立索引。
④查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度。
⑤查詢中統計或者分組字段。
哪些情況不適合建索引:
①頻繁更新的字段。
②Where 條件中用不到的字段。
③表記錄太少。
④經常增刪改的表。
⑤散列太小的字段,如性別、國籍。
索引優化就是為了盡可能的利用索引來提高查詢的效率,所以保證索引不失效,並且創建正確的索引與高效的sql語句,就是對索引的優化,因此關於優化直接看下個題目:索引的失效。
2)哪些情況下索引失效。
索引優化和索引失效是相對應的,我們優化索引的目的就是為了讓索引不失效,發生下列情況索引會失效:
①對於使用NOT NULL修飾的字段,使用IS NULL和 IS NOT NULL,會導致索引失效,進行全表掃描。
②鍵值較少的列。因為鍵值較少,如果加上索引,還需要對索引進行維護,本來記錄就少,所以直接查詢效率更高。
③LIKE以%開頭會導致索引失效。如果右邊加上%,索引不會失效,但是在實際生產環境中,如果只在右邊加%,對於模糊查詢不夠用。解決方式:使用索引覆蓋:查詢字段和條件字段都在索引列上時,索引才會生效。
④使用范圍后(如字段>1)會使索引失效(存儲引擎不能使用索引中范圍條件右邊的列)。所以如果存在范圍查詢的字段,就不要建立索引。
⑤對於兩張表,如果基於主鍵的查詢,是可以用索引的,因為主鍵本身就有索引,對於左右連接來說,左連接,左表肯定是All,本來就要查詢出左表的結果,所以右表建立索引,而右連接相反,左表建立索引。
⑥不要在索引列上做任何操作(計算、函數和類型轉換),會導致索引失效,另外在字符串查詢不加單引號,也會導致索引失效。
⑦最左前綴法則:查詢從索引列的最左開始(頭部),如果沒有頭部,則會使用全表掃描,並且中間不能間斷,如只有頭部和尾部,則只使用頭部索引。火車頭不能少,中間車廂不能斷。
⑧使用不等於的時候會使索引失效,導致全表掃描。
⑨盡量使用覆蓋索引:索引列和查詢列一致。
⑩OR連接會使索引失效,導致全表掃描。
⑪Order By 要盡量使用 Index 排序,避免 Filesort 排序。
3)MySql調優項目經歷或者相關策略。
是否需要添加索引,在哪些字段上添加索引,在sql語句中,索引列是否用上,主要使用Explain對sql語句進行分析。
這里對Explain進行簡單介紹:
使用 Explain 關鍵字可以模擬優化器執行 Sql 查詢語句,從而知道 Mysql 是如何處理 Sql 的。
執行Explain會產生一個信息表,表中有如下關鍵字:
①id:select查詢的序列號,表示查詢中執行select子句或操作表的順序。值越大越先執行,值相同,從上到下依次執行。
②select_type:有6種取值SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION、UNION RESULT,其值具體解釋,參考:https://yq.aliyun.com/articles/61934
③table:顯示當前行sql是對哪張表進行操作的。
④type:指訪問類型,非常重要,根據type可推斷sql語句的優劣。其取值從最好到最差依次是:system > const > eq_ref > ref > range > index > all,通常需保證到range級別,最好能達到ref級別。
#1.const:表示通過索引一次就找到了,用於比較主鍵索引或者唯一性索引。如將主鍵置於 Where 條件中,Mysql 就能將該查詢轉換為一個常量。
#2.system:表示只有一行數據,是const的特例,生產中基本不會出現,可忽略。
#3.eq_ref:唯一性索引掃描。對於每個索引表中只有一條記錄與之匹配。常見於主鍵或唯一索引掃描。
#4.ref:非唯一性索引掃描,返回匹配某個單獨值的所有行。對於 eq_ref & ref 的總結:都會使用索引,但使用索引進行檢索后的結果不同,前者的結果是唯一的,而后者的結果不唯一。所以,前者通常用於主鍵或唯一性索引掃描,而后者通常用於非唯一性索引掃描(有多行記錄)。
#5.range:只檢索給定范圍的行,使用一個索引來選擇行;Key 列顯示使用了哪個索引;一般就是在 Where 條件中出現了 between, <, >, in 等查詢;它比全索引掃描要好,因為它開始於索引的某一點、且結束於另一點,而不用全索引掃描.
#6.index:全索引掃描,只遍歷索引樹,index和all 都是全表掃描,但是 index 是從索引中讀取,而 All 是從磁盤中讀取。
#7.All:全表掃描,磁盤掃描。
⑤possible_keys:顯示理論上有可能應用在這張表中的索引,一個或多個。查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被實際使用。
⑥key:實際使用的索引。如果為 Null,則未使用索引。查詢中若使用了覆蓋索引,則該索引只出現在 Key 列表中(即不會出現在 possible_keys 列中)。
⑦key_len:表示索引中使用的字節數,可通過該值計算查詢中使用的索引長度。在不損失精確性的情況下,長度越短越好。顯示的值為索引字段的最大可能長度,並非實際使用長度,即 key_len 是根據表定義計算而得,不是通過表內檢索出的。
⑧ref:顯示索引的哪一列被使用了,如果索引被使用則是一個常數。表示哪些列或常量被用於查找索引列上的值。
⑨rows:根據表統計信息及索引選用情況,大致估算出查詢到結果時所需要讀取的行數(要跑多少行)。值越小越好(值越小說明查詢越精准)。
⑩Extra
會出現的值包括:
#1.Using filesort:說明 Mysql 會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行排序;Mysql 中無法利用索引完成的排序操作稱為“文件排序”。因此出現該值,表示sql語句比較“爛”了,則需要進行sql語句的優化。
#2.Using Temporary:使用了臨時表保存中間結果,Mysql 在查詢結果排序時使用臨時表,常見於 ORDER BY 和 GROUP BY。出現該值,則表明sql非常“爛”了,急需優化。
#3.Using Where:表明索引被用來執行索引鍵值的查找。
#4.Using Index:表示相應的 SELECT 操作中使用了覆蓋索引,避免訪問了表的數據行,效率可以。
總結:
type、key、ref、Extra,這四個字段比較重要,sql語句的“爛”的程度,通過這幾個字段體現。
type:取值從最好到最差依次是:system > const > eq_ref > ref > range > index > all,查詢時至少保證在range,最好達到ref。
key:實際使用的索引,如果為NULL,則表示未使用索引。
ref:顯示那一列索引被使用了。
Extra:最好是Using Index、Using Where,一定不能是Using Temporary、Using filesort。
5)MySql的事務隔離級別,不可重復讀、臟讀、幻讀。
MySql的事務隔離級別有4個,隔離等級從低到高依次為Read uncommitted (讀取未提交內容)、Read committed(讀取提交內容) 、Repeatable read(可重復讀) 、Serializable (串行),這四個級別可以逐個解決臟讀 、不可重復讀 、幻讀這幾類問題,其中Repeatable read是MySql事務的默認隔離級別。
從表中可以看出Serializable隔離等級最高,可以避免一切並發問題,但是效率低。
臟讀:A事務更新一份數據,但事務未提交,B事務在此時讀取了同一份數據,由於某些原因,A事務發生了回滾操作,則B事務拿着失效的數據去做操作就會發生錯誤。臟讀通俗來說就是讀錯了,讀錯了。
不可重復讀:對於不可重復讀的解釋很多資料說得非常模糊,這里給出一個比較清晰的解釋。A事務兩次讀取同一數據,在A事務還沒有結束時,B事務也訪問該同一數據,並進行了修改。那么在A事務中的兩次讀數據之間,由於B事務的修改,A事務兩次讀到的的數據可能是不一樣的。這樣就發生了在一個事務內兩次讀到的數據是不一樣的,因此稱為是不可重復讀。(即在重復對數據進行讀取的時候,不能得到相同的數據內容,感覺這個不可重復讀翻譯很不好理解,個人的理解方式:不可重復讀,那重復讀會出現什么情況呢,重復讀出現數據不一致的情況,所以還是不要重復讀——>不可重復讀)
例如,一個編輯人員兩次讀取同一文檔,但在兩次讀取之間,作者重寫了該文檔。當編輯人員第二次讀取文檔時,文檔已更改,則編輯第二次讀取的文檔與第一次就不一致了。
幻讀:通俗來講讀取到的數據像產生幻覺一樣。是指當事務不是獨立執行時發生的一種現象。事務A在兩次查詢的過程中(比如查詢結果8列),事務B對該表進行了插入、刪除操作(增加或減少了2列),從而事務A第二次查詢的結果發生了變化,兩次查詢的數據不一樣,感覺產生了“幻覺”一樣。
虛讀:通俗來講讀取的數據不同。A事務在兩次查詢的過程中(查詢結果一列),B事務對數據進行了修改,從而使A事務第二次查詢的結果不一樣。
臟讀的事務未提交,虛讀與幻讀事務已經提交。
Read uncommitted(讀未提交內容)
在該級別下,A事務對一行數據修改的過程中,不允許B事務對該行數據進行修改,但允許B事務對該行數據進行讀操作。 因此本級別下,不會出現更新丟失(i++問題),但會出現臟讀(A修改時,發生了回滾)、不可重復讀(B兩次讀取時,A修改了數據),幻讀(幻讀是不可重復讀的一種情況)。
Read committed(讀提交內容)
在該級別下,未提交的寫事務不允許其他事務訪問該行,因此不會出現臟讀;但是讀取數據的事務允許其他事務的訪問該行數據,因此會出現不可重復讀的情況。A讀取數據,B緊接着A更改了數據,並提交了事務,A再次讀取數據時,發現數據已經改變。出現不可重復讀和幻讀想象。
Repeatable read(可重復讀)
在該級別下,讀事務時禁止寫事務(讀寫互斥),A在讀取數據時數據為100,事務提交后,緊接着B對數據修改為200,當A再次讀取時,發現數據不一樣,出現幻讀。
Serialiazble read(串行)
隔離級別最高,避免一切並發問題,但效率低,生產中基本不用。
6)delete 與 truncate 區別,分別適用於哪種場景。
delete與truncate都是做刪除操作,但是兩者間還是有一定區別:
①truncate刪除速度快,沒有日志記錄,數據不可恢復。釋放表或索引的空間
②delete刪除速度慢,因為刪除中會產生日志記錄,數據可恢復。不會釋放表或索引的空間。
③應用場景這個不好說,delete可恢復,truncate不可恢復,只有根據具體需求進行選擇了。
7)MySql中主從復制,集群。
MySql提供主從復制的功能,基礎是二進制日志文件。
關於集群方面,功力不深,需要更進一步的了解,才能很好的回答該問題。
參考:
https://www.cnblogs.com/gl-developer/p/6170423.html
8)B+樹、為什么使用 B+樹、B+樹優缺點
關於B+樹,筆者並不是特別的了解。放上一鏈接:https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/03.02.md
為什么使用B+樹?
①B+樹支持區間查詢,而B樹不支持。
②B+樹方便掃庫,它直接從葉子節點出發,就可以進行掃描,而B樹需進行中序遍歷(LDR)。
③B+樹磁盤讀寫代價更低。
缺點:
①當查找數據在非葉子節點時,B+樹會走一條根到葉子節點的路徑。
參考:
https://www.cnblogs.com/tiancai/p/9024351.html
http://darrenzhu.iteye.com/blog/2050082
9)MySql存儲引擎MyISAM和InnoDB的區別。
①MyISAM不支持外鍵,InnoDB支持外鍵。
②MyISAM不支持事務,InnoDB支持事務。
③MyISAM是表鎖,InnoDB是行鎖。
④MyISAM支持全文索引,InnoDB不支持。
⑤MyISAM的查詢速度比InnoDB快。
參考:
https://www.cnblogs.com/changna1314/p/6878900.html
by Shawn Chen,於2018.6月,開始找工作途中......