04. MySQL數據庫索引知識點總結

面試官:當一條查詢執行較慢時一般能夠如何進行優化
我:加索引!
面試官:那麼到底什麼是索引,其底層又是如何實現的呢
我:懵逼!mysql

索引的常見模型面試

索引的出現是爲了提升查詢效率,就像書的目錄同樣sql

常見的實現索引的模型有:哈希表、有序數組和搜索樹
哈希表:鍵 - 值(key - value)。
哈希思路:把值放在數組裏,用一個哈希函數把key換算成一個肯定的位置,而後把value放在數組的這個位置
哈希衝突的處理辦法:鏈表
哈希表適用場景:只有等值查詢的場景
有序數組:按順序存儲。查詢用二分法就能夠快速查詢,時間複雜度是:O(log(N))
有序數組查詢效率高,更新效率低
有序數組的適用場景:靜態存儲引擎。
二叉搜索樹:每一個節點的左兒子小於父節點,父節點又小於右兒子
二叉搜索樹:查詢時間複雜度O(log(N)),更新時間複雜度O(log(N))
數據庫存儲大多不適用二叉樹,由於樹高太高,會適用N叉樹
擴展:爲何樹高太高就很差呢?
樹高表示N叉樹的層數,首先,層數越高佔用空間就越大,同時層數越高表示查找到目標數據所要跳層的次數越大,層與層(其實是父節點與父節點)之間是經過指針鏈接的,而兩個節點的內存地址是連續的機率很低,所以就會觸發磁盤隨機讀效率較低 當索引有100萬數據,樹高20(2的20次方) 一次查詢可能須要跳躍 20 個數據塊數據庫

哈希表 是一種以鍵-值(key-value)存儲數據的結構,咱們只要輸入待查找的值即key,就能夠找到其對應的值即Value。哈希的思路很簡單,把值放在數組裏,用一個哈希函數把key換算成一個肯定的位置,而後把value放在數組的這個位置。(與HashMap相似)
優勢:效率高
缺點:由於不是有序的,因此哈希索引作區間查詢的速度是很慢的。數組

你能夠設想下,若是你如今要找某字段在[a, b]這個區間的數據,就必須所有掃描一遍了。緩存

因此,哈希表這種結構適用於只有等值查詢的場景,不適用於區間查詢數據結構

有序數組 等值查詢和範圍查詢場景中的性能就都很是優秀數據庫設計

搜索樹模型又能夠細分爲二叉樹紅黑樹B+樹函數

索引的實現由存儲引擎來決定,InnoDB索引的實現使用B+樹模型
二叉樹和紅黑樹的搜索效率很高,可是應用在數據庫中時由於數據量較大,二叉樹和紅黑樹每次只分裂出兩個分支,致使分裂層數很大,空間佔用率高
而B+樹選擇增長分支樹,把整顆樹的高度維持在很小的範圍內,同時在內存裏緩存前面若干層的節點,能夠極大地下降訪問磁盤的次數,提升讀的效率。
同時要注意的一點是:二叉樹類數據結構效率高的前提是數據有序,這也是數據庫常存在一個自增主鍵的緣由性能

擴展:什麼是B+樹

B-樹 即Balance-tree即B樹

B-樹模型

B+樹 B+樹索引並不能找到一個給定鍵值的具體行。B+樹索引能找到的只是被查找數據行所在的頁。而後數據庫經過把頁讀入到內存,再在內存中進行查找,最後獲得要在找的數據。由於頁目錄中的槽是按照主鍵順序排列的,因此在每個頁目錄中,經過二分查找,定位到數據行所在的頁,而後將整個頁讀入內存
B+樹模型
擴展:咱們能夠人工調整頁的大小嗎?
全部的innodb索引都是btree索引,索引記錄保存在葉子上,默認的索引頁大小是16K。當有新的記錄插入時,innodb出於對未來的insert和update操做的考慮,會嘗試留下1/16的空閒頁大小。

若是索引記錄是徹底按照索引記錄的大小順序插入的,那麼索引也將填滿整個頁大小的15/16,若是插入順序徹底隨機,那麼索引頁基本上填充爲1/2至15/16自建。若是填充因子低於1/2,innodb會嘗試重建b-tree。

Mysql5.6之後,能夠經過innodb_page_size參數設置當前實例下每一個索引頁的大小,一旦設定,沒法再更改回來。推薦的配置通常是16K,8K或者4K。另外假如一個Mysql實例設置了不一樣於默認值的innodb_page_size A,那麼將沒法使用其餘不一樣於A值的實例上的文件(好比作一個物理備份和恢復)

B*樹 是B+樹的變體,在B+樹的非根和非葉子結點再增長指向兄弟的指針

B*樹模型

B樹模型小結:

B(B-)樹:多路搜索樹,每一個結點存儲M/2到M個關鍵字,非葉子結點存儲指向關鍵字範圍的子結點;全部關鍵字在整顆樹中出現,且只出現一次,非葉子結點能夠命中;
B+樹:在B-樹基礎上,爲葉子結點增長鏈表指針,全部關鍵字都在葉子結點中出現,非葉子結點做爲葉子結點的索引;B+樹老是到葉子結點才命中;
B*樹:在B+樹基礎上,爲非葉子結點也增長鏈表指針,將結點的最低利用率從1/2提升到2/3;

說完底層實現咱們來講一下表層

索引的種類

普通索引:僅加速查詢

惟一索引:加速查詢 + 列值惟一(能夠有null)

主鍵索引:加速查詢 + 列值惟一(不能夠有null)+ 表中只有一個

聯合索引:多列值組成一個索引,專門用於組合搜索,其效率大於索引合併

全文索引:對文本的內容進行分詞,進行搜索

ps.索引合併,使用多個單列索引組合搜索
覆蓋索引,select的數據列只用從索引中就可以取得,沒必要讀取數據行,換句話說查詢列要被所建的索引覆蓋
聯合索引本質:

當建立(a,b,c)聯合索引時,至關於建立了(a)單列索引,(a,b)聯合索引以及(a,b,c)聯合索引。想要索引生效的話,只能使用 a和a,b和a,b,c三種組合;固然,a,c組合也能夠,但實際上只用到了a的索引,c並無用到!只用bc兩個條件不會用到索引。
聯合索引比對每一個列分別建索引更有優點
由於索引創建得越多就越佔磁盤空間,在更新數據的時候速度會更慢。另外創建多列索引時,順序也是須要注意的,應該將嚴格的索引放在前面,這樣篩選的力度會更大,效率更高。
前綴索引
有時候一個字段很長,咱們只須要截取前幾位或後幾位(反轉後取前幾位)創建索引便可,節約了空間同時也能實現相同的效果
索引下推優化
沒太懂,自行百度

索引失效場景
一、若是條件中有or,除非條件中的列所有有索引不然不會使用索引查詢
二、like查詢是以%開頭(可是以%結尾卻不會失效)
三、若是列類型是字符串,那必定要在條件中將數據使用引號引用起來,不然不使用索引。(例如where ID = 3 和 where ID = "3")
四、若是mysql估計使用全表掃描要比使用索引快,則不使用索引。(由於server層有優化器)
五、索引不會包含有null值的列,只要列中包含有null值都將不會被包含在索引中,複合索引中只要有一列含有null值,那麼這一列對於此複合索引就是無效的。因此咱們在數據庫設計時不要讓字段的默認值爲null。
六、在列上進行運算將致使索引失效
注意點:
雖然索引大大提升了查詢速度,同時卻會下降更新表的速度,如對錶進行insert、update和delete。由於更新表時,不只要保存數據,還要保存一下索引文件。因此對數據量不大,查詢率不高更新率高的的列添加索引反而得不償失。
短索引
對串列進行索引,若是可能應該指定一個前綴長度。例如,若是有一個char(255)的列,若是在前10個或20個字符內,多數值是唯一的,那麼就不要對整個列進行索引。短索引不只能夠提升查詢速度並且能夠節省磁盤空間和I/O操做。
索引回表
咱們知道,通常查詢數據時都是根據索引找到對應的索引id而後拿着索引id找到對應的數據,這個過程稱爲回表
覆蓋索引
若是執行的語句是select ID from T where k between 3 and 5此時咱們要查的數據就是索引,所以能夠直接提供查詢結果,不須要回表。也就是說,在這個查詢裏面,索引k已經「覆蓋了」咱們的查詢需求,咱們稱爲覆蓋索引。

問題:針對上面說的索引失效第四條 那麼什麼狀況下使用索引反而沒有全表掃描快?好比你要從一本字典中找到某一個字,使用目錄查確定很快,可是我如今要找到全部拼音a-x開頭的字,走全表掃描就是直接翻,走索引須要將每一個數據根據目錄一層一層的去找反而變慢了。

相關文章
相關標籤/搜索