數據庫:MySQL高頻面試題,大廠必備!

 
   

一、MySQL 索引使用什麼數據結構?爲何用 B+作索引?

使用B+樹。php

這個問題,能夠在腦子裏面先思考一下,若是讓你來設計數據庫的索引,你會怎麼設計?html

咱們仍是用Why?What?How?三步法來看這個問題。java

爲何會須要索引?索引是什麼?索引怎麼用的?mysql

再思考爲何須要B+樹?B+樹是什麼?B+樹怎麼用?程序員

答:大部分程序主要的功能都是對數據的處理,寫入、查詢、轉化、輸出。最形象的比喻就是樹和內容和目錄的關係,目錄就是索引,咱們根據目錄能快速拿到想要內容的頁碼。sql

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

爲何是B+樹,有這個幾個理由:數據庫

  • 若是是用AVL平衡二叉樹,樹高度過高,索引查詢須要訪問磁盤,每次訪問以節點爲單位進行磁盤I/O ,須要儘可能減小數據讀取的I/O操做,因此樹高度必定不能過高,存儲千萬級別的數據,實踐中 B+ 樹的高度也就 4或者5。緩存

  • B+樹常常用來比較的是B樹,B+樹相比B樹有個很大的特色是B+樹全部關鍵字都出如今葉子結點的鏈表中(稠密索引),且鏈表中的關鍵字剛好是有序的,對於範圍查找,好比15~50,B樹須要中序遍歷二叉樹,可是B+樹直接在葉子節點順序訪問就能夠了。性能優化

二、什麼是最左匹配原則?

首先說明一點:數據結構

最左前綴匹配原則:在MySQL創建聯合索引時會遵照最左前綴匹配原則,即最左優先,在檢索數據時從聯合索引的最左邊開始匹配。

打個比方,咱們有張student 表,咱們根據學院編號+班級創建了一個聯合索引 index_magor_class(magor,class), 這個索引由二個字段組成。

索引的底層是一顆B+樹,那麼聯合索引的底層也就是一顆B+樹,只不過聯合索引的B+樹節點中存儲的是逗號分隔的多個值。

舉例:建立一個 index_magor_class(magor,class) 的聯合索引,那麼它的索引樹就是下圖的樣子。

它是先根據magor排序,再根據class排序,若是索引後面還有字段,繼續以此類推。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

咱們查詢的where 條件若是隻傳入了班級,是走不到聯合索引的,可是若是隻傳了學院編號,是可能會走到聯合索引的。(爲何說可能,MYSQL的執行計劃和查詢的實際執行過程並不徹底吻合,好比你數據庫數據量不多,可能直接全量遍歷速度更快,就不走索引了)

三、在建表的時候如何設計索引的?有沒有作過索引優化 ?

一、利用覆蓋索引來進行查詢操做,來避免回表操做。

說明:若是一本書須要知道第11章是什麼標題,會翻開第11章對應的那一頁嗎?目錄瀏覽一下就好,這個目錄就是起到覆蓋索引的做用。

什麼意思,好比你主鍵索引是學號,你寫select 語句的時候,直接select 學號 from table 就能夠了,不用select 其餘字段,通常除非很是有必要,儘可能按需select 字段,少用或不用 select, 否則還須要回表。

這裏我解釋一下回表,好比咱們表主鍵索引是學號,另外咱們還根據手機號也建了索引,若是咱們where 條件是手機號,分二種狀況:

正例:IDB可以創建索引的種類分爲【主鍵索引、惟一索引、普通索引】,而覆蓋索引是一種查詢的一種效果,用explain的結果,extra列會出現:using index.

  • 若是咱們select 獲取的字段是學號,直接在手機號的索引表就能獲取到數據,不須要回表;

  • 若是咱們select 的時候還有其餘字段,咱們查詢的時候流程是這樣的,先根據手機號查到學號,再根據學號去主鍵索引表查詢數據,這個過程叫回表。

二、業務上具備惟一特性的字段,即便是組合字段,也建議建成惟一索引。說明:不要覺得惟一索引影響了insert速度,這個速度損耗能夠忽略,但提升查找速度是明顯的;另外,即便在應用層作了很是完善的校驗和控制,只要沒有惟一索引,根據墨菲定律,必然有髒數據產生。

三、超過三個表禁止join。須要join的字段,數據類型保持絕對一致;多表關聯查詢時,保證被關聯的字段須要有索引。說明:即便雙表join也要注意表索引、SQL性能。

四、在varchar字段上創建索引時,必須指定索引長度,不必對全字段創建索引,根據實際文本區分度決定索引長度。說明:索引的長度與區分度是一對矛盾體,通常對字符串類型數據,長度爲20的索引,區分度會高達90%以上,可使用count(distinct left(列名, 索引長度))/count(*)的區分度來肯定。

五、頁面搜索嚴禁左模糊或者全模糊,若是須要請走搜索引擎來解決。說明:索引文件具備B-Tree的最左前綴匹配特性,若是左邊的值未肯定,那麼沒法使用此索引。

六、SQL性能優化的目標:至少要達到 range 級別,要求是ref級別,若是能夠是const最好。說明:

  • 1)const 單表中最多隻有一個匹配行(主鍵或者惟一索引),在優化階段便可讀取到數據。

  • 2)ref 指的是使用普通的索引。(normal index)

  • 3)range 對索引進行範圍檢索。反例:explain表的結果,type=index,索引物理文件全掃描,速度很是慢,這個index級別比較range還低,與全表掃描是小巫見大巫。

七、建組合索引的時候,區分度最高的在最左邊。正例:若是where a=? and b=? ,a列的幾乎接近於惟一值,那麼只須要單建idx_a索引便可。說明:存在非等號和等號混合判斷條件時,在建索引時,請把等號條件的列前置。如:where c>? and d=? 那麼即便c的區分度更高,也必須把d放在索引的最前列,即創建組合索引idx_d_c。

八、防止因字段類型不一樣形成的隱式轉換,致使索引失效。

四、MyBatis用過嗎? 一二級緩存清楚嗎?

  • 一級緩存
    Mybatis的一級緩存是指SQLSession,一級緩存的做用域是SQlSession, Mabits默認開啓一級緩存。在同一個SqlSession中,執行相同的SQL查詢時;第一次會去查詢數據庫,並寫在緩存中,第二次會直接從緩存中取。當執行SQL時候兩次查詢中間發生了增刪改的操做,則SQLSession的緩存會被清空。每次查詢會先去緩存中找,若是找不到,再去數據庫查詢,而後把結果寫到緩存中。Mybatis的內部緩存使用一個HashMap,key爲hashcode+statementId+sql語句。Value爲查詢出來的結果集映射成的java對象。SqlSession執行insert、update、delete等操做commit後會清空該SQLSession緩存。

  • 二級緩存
    二級緩存是 mapper級別的,Mybatis默認是沒有開啓二級緩存的。第一次調用mapper下的SQL去查詢用戶的信息,查詢到的信息會存放在該mapper對應的二級緩存區域。第二次調用namespace下的mapper映射文件中,相同的sql去查詢用戶信息,會去對應的二級緩存內取結果。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

五、MySQL 主從同步怎麼作的?binlog清楚嗎?

  • Master 數據庫只要發生變化,立馬記錄到Binary log 日誌文件中

  • Slave數據庫啓動一個I/O thread鏈接Master數據庫,請求Master變化的二進制日誌

  • Slave I/O獲取到的二進制日誌,保存到本身的Relay log 日誌文件中。

  • Slave 有一個 SQL thread定時檢查Realy log是否變化,變化那麼就更新數據

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

六、MySQL 有沒有作分庫分表?怎麼設計的?

Why?:

當一張表的數據達到幾千萬時,你查詢一次所花的時間會變多,若是有聯合查詢的話,我想有可能會死在那兒了。分表的目的就在於此,減少數據庫的負擔,縮短查詢時間。

mysql中有一種機制是表鎖定和行鎖定,是爲了保證數據的完整性。表鎖定表示大家都不能對這張表進行操做,必須等我對錶操做完才行。行鎖定也同樣,別的sql必須等我對這條數據操做完了,才能對這條數據進行操做。

When?(何時須要分表?):

單錶行數超過500萬行或者單表容量超過2GB,才推薦進行分庫分表。說明:若是預計三年後的數據量根本達不到這個級別,請不要在建立表時就分庫分表。

反例:某業務三年總數據量才2萬行,卻分紅1024張表,問:你爲何這麼設計?答:分1024張表,不是標配嗎?

How?(分庫分表有幾種策略):

垂直拆分 or 水平拆分

拆分中間件,詳細能夠參考:

  • Sharding-sphere,前身是sharding-jdbc;噹噹的分庫分表中間件

  • TDDL:jar,Taobao Distribute Data Layer;

  • Mycat:中間件。

注:工具的利弊,請自行調研,官網和社區優先。

  • 按照userId緯度拆分,安琪拉見過的常見的有,根據 userId % 64 取模拆0~63編號的64張表,

  • 固定位拆,取userId 指定二位,例如倒數2,3位組成00~99 一共100張表的,百庫表表。

  • hash: userId hash一下,而後 % 表數;

  • Range: 另外還有按照userId 指定範圍拆的,0-1千萬一張表,這種用的比較少,容易產生熱點。

  • 把不一樣業務域的表拆成不一樣庫,例如訂單相關表、用戶信息相關表、營銷相關表分開在不一樣庫;

  • 把大字段獨立存儲到一張表中

  • 把不經常使用的字段單獨拿出來存儲到一張表

七、用userId作的分庫分表,如今須要用電話號碼查詢怎麼辦?

和回表邏輯同樣,單獨建一個電話號碼索引表,存放電話號碼和userId,查詢時先根據電話號碼查詢userId,而後再根據userId查詢數據。

IT技術分享社區

我的博客網站:https://programmerblog.xyz

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

文章推薦程序員效率:畫流程圖經常使用的工具程序員效率:整理經常使用的在線筆記軟件遠程辦公:經常使用的遠程協助軟件,你都知道嗎?51單片機程序下載、ISP及串口基礎知識硬件:斷路器、接觸器、繼電器基礎知識

相關文章
相關標籤/搜索