(轉載)原文連接:blog.csdn.net/fujiandiyi0…前端
你們好,我渣渣煙。我曾經寫過一篇《面試官:談談你對錶設計的認識?》因而呢,決定再來一個mysql的數據庫專題,這篇咱們就來談談關於索引方面的mysql面試題。仍是老規矩,講的是在Innodb存儲引擎下的情形,畢竟我還真沒用過Mysiam之類的存儲引擎。ps:其實很早就想寫了,一直偷懶!mysql
其實這下面每一個問題,我均可以講一篇文章出來!並且這些問題,不是我憑空編的。以下圖所示(注意看第三題)面試
因此我回憶了一下,索引常見考點有哪些,總結成了這篇文章! 主要題目有下面這些sql
(1)你通常怎麼建索引的?數據庫
(2)講講索引的分類?你知道哪些?後端
(3)如何避免回表查詢?什麼是索引覆蓋?緩存
(4)如今我有一個列,裏頭的數據都是惟一的,須要建一個索引,選惟一索引仍是普通索引?bash
(5)mysql索引是什麼結構的?用紅黑樹能夠麼?服務器
(6)mysql某表建了多個單索引,查詢多個條件時如何走索引的?網絡
一、你通常怎麼建索引的?煙哥注:曾記得有一個粉絲來找個人時候,出現以下搞笑一幕
渣渣煙:"你這個簡歷上寫了擁有SQL優化經驗,你怎麼建索引的?"
只見該粉絲嘿嘿一笑..說道:"就那樣建啊…"
渣渣煙:"噢(第二聲),就哪樣建啊…"
粉絲:"…就網上說的那些索引規則啊"
渣渣煙:"那你怎麼知道那些SQL出問題,須要建索引呢?"粉絲:"我….."
複製代碼
嗯,這道題其實很基礎。可是有沒有作過,這題是能夠看出來的。
打開慢查詢日誌
slow_query_log=1
慢查詢日誌存儲路徑
slow_query_log_file=/var/log/mysql/log-slow-queries.log
SQL執行時間大於3秒,則記錄日誌
long_query_time=3
複製代碼
監控到慢SQL後,就立刻開始建索引?例如,當只要一行數據時使用 limit 1
然而大多數狀況下,業務SQL十分複雜,無法優化。因此就要創建索引了。這個時候,參照以下規則創建索引
(1)索引並不是越多越好,大量的索引不只佔用磁盤空間,並且還會影響insert,delete,update等語句的性能
(2)避免對常常更新的表作更多的索引,而且索引中的列儘量少;對常常用於查詢的字段建立索引,避免添加沒必要要的索引
(3)數據量少的表儘可能不要使用索引,因爲數據較少,查詢花費的時間可能比遍歷索引的時間還要短,索引可能不會產生優化效果
(4)在條件表達式中常常用到不一樣值較多的列上建立索引,在不一樣值不多的列上不要創建索引。好比性別字段只有「男」「女」倆個值,就無需創建索引。若是創建了索引不但不會提高效率,反而嚴重減低數據的更新速度
(5)在頻繁進行排序或者分組的列上創建索引,若是排序的列有多個,能夠在這些列上創建聯合索引。
二、講講索引的分類?你知道哪些?
從物理存儲角度: 聚簇索引和非聚簇索引 從數據結構角度: B+樹索引、hash索引、FULLTEXT索引、R-Tree索引 從邏輯角度:
主鍵索引:主鍵索引是一種特殊的惟一索引,不容許有空值
普通索引或者單列索引
多列索引(複合索引):複合索引指多個字段上建立的索引,只有在查詢條件中使用了建立索引時的第一個字段,索引纔會被使用。使用複合索引時遵循最左前綴集合
惟一索引或者非惟一索引
空間索引:空間索引是對空間數據類型的字段創建的索引,MYSQL中的空間數據類型有4種,分別是GEOMETRY、POINT、LINESTRING、POLYGON。
三、如何避免回表查詢?什麼是索引覆蓋?
這個問題,若是要看詳細版,請參閱文章《Innodb中索引的原理》
這裏簡單說一下。
例如此時有一張表table1,有一個聯合索引(a,b)
執行以下SQL
select a,b from table1
複製代碼
在索引上就能找到結果,就不用回表去查詢!
select a,b,c from table2
複製代碼
c列在索引上不存在,就須要回表查詢。
須要說明的是覆蓋索引必需要存儲索引列的值,而哈希索引、空間索引和全文索引不存儲索引列的值,因此mysql只能用B+ tree索引作覆蓋索引。
四、如今我有一個列,裏頭的數據都是惟一的,須要建一個索引,選惟一索引仍是普通索引?
【強制】業務上具備惟一特性的字段,即便是多個字段的組合,也必須建成惟一索引
說明:不要覺得惟一索引影響了 insert 速度,這個速度損耗能夠忽略,但提升查找速度是明顯的;另外,即便在應用層作了很是完善的校驗控制,只要沒有惟一索引,根據墨菲定律,必然有髒數據產生。
複製代碼
那好,下一問出現了!
爲何惟一索引的插入速度比不上普通索引?爲何惟一索引的查找速度比普通索引快?
這麼作的優勢:能將多個插入合併到一個操做中,就大大提升了非聚簇索引的插入性能。
InnoDB 從 1.0.x 版本開始引入了 Change Buffer,能夠算是對 Insert Buffer 的升級。從這個版本開始,InnoDB 存儲引擎能夠對 insert、delete、update 都進行緩存。
惟一速度的插入比普通索引慢的緣由就是:
惟一索引沒法利用Change Buffer
普通索引能夠利用Change Buffer
因而乎下一問又來了!爲何惟一索引的更新不使用 Change Buffer?
由於惟一索引爲了保證惟一性,須要將數據頁加載進內存才能判斷是否違反惟一性約束。可是,既然數據頁都加載到內存了,還不如直接更新內存中的數據頁,沒有必要再使用Change Buffer。
最後回答一下,惟一索引的搜索速度比普通索引快的緣由就是:
普通索引在找到知足條件的第一條記錄後,還須要判斷下一條記錄,直到第一個不知足條件的記錄出現。
惟一索引在找到知足條件的第一條記錄後,直接返回,不用判斷下一條記錄了。
五、mysql索引是什麼結構的?用紅黑樹能夠麼?
那爲啥不用B Tree,而選擇B+ tree呢?
注意一下B tree的兩個明顯特色
樹內存儲數據
葉子節點上無鏈表
而B+ tree長下面這樣的
注意一下B+ tree的兩個明顯特色
數據只出如今葉子節點
全部葉子節點增長了一個鏈指針
接下來就能夠開始編了~~好比數據庫索引採用B+ tree的主要緣由是B Tree在提升了磁盤IO性能的同時並無解決元素遍歷的效率低下的問題。正是爲了解決這個問題,B+ tree應運而生。B+ tree只要遍歷葉子節點就能夠實現整棵樹的遍歷。並且在數據庫中基於範圍的查詢是很是頻繁的,若是使用B Tree,則須要作局部的中序遍歷,可能要跨層訪問,效率太慢。
提示,我下一問就是:
六、mysql某表建了多個單索引,查詢多個條件時如何走索引的?
這裏但願你們先看看個人另外一篇文章
Mysql在優化器中有一個優化器稱爲Range 優化器,負責進行範圍查詢的優化!
它們是MySQL優化器對開銷代價的估算方法,前者統計速度慢可是能獲得精準的值,後者統計速度快可是數據未必精準。
坦白說寫到這裏,我心裏聲淚俱下,要把index dive和index statistics寫明白,真不是一件容易的事,這裏只能稍微扯扯。
對於index dive:
COST = CPU COST + IO COST
複製代碼
其中CPU COST指的是處理返回記錄所花的開銷。而IO COST指的是讀取頁面的開銷。
mysql會對每種索引的執行狀況,進行上述成本計算,最後以成本小的方式進行執行。
可是呢,在某些狀況下mysql執行index dive的成本太大。所以優化器會選擇以index statistics方式進行估算成本。
SHOW INDEX FROM tbl_name [FROM db_name]
複製代碼
此時出來的結果中,有一列名爲Cardinality,該值表示索引列中不重複值的個數。Cardinality值越大,就意味着,使用索引能排除越多的數據,執行也更爲高效。
若是文章對您有幫助,關注一下⬇️再走吧!
Linux服務器和網絡協議必備文檔
千萬級數據庫必備知識
後端開發小白到大神必備文檔
前端必備乾貨