一、索引:
1. 索引的概念:
索引是幫助Mysql高效獲取數據的排好序的數據結構
2. 索引存儲在文件里:
mysql主要有兩種存儲引擎: Myisam、Innodb兩種
對於存儲引擎為Myisam的數據表中,有三種文件格式,以.frm為后綴的表結構文件、以MYD為后綴的數據文件,以MYI為后綴的索引文件;
對於存儲引擎為Innodb的數據表中,有兩種文件格式,以.frm為后綴的表結構文件、以ibd為后綴的索引與數據合並的文件
myisam索引實現: 非聚集索引(索引文件和數據文件是分離的)
Innodb索引(聚集索引)
二、索引的各種存儲結構及其優缺點
在開始講這一小節之前,我們先來看一下在數據庫沒有加索引的情況下,SQL中的where字句是如何查找目標記錄的。
我們先看下左邊表格第二列Col2列的數據時如何查找的,如果我們希望查找where Col2 = 22的記錄,我們在沒加索引的情況下是按順序從第一條記錄查找,由此可知需要查找5次才能找到;
如果對Col2字段加上索引后,我們假設使用最簡單的二叉樹作為索引存儲方式,再次查找where Col2 = 22的記錄這次只需要查找2次就能找到目標記錄,效率提高十分明顯。
1. 二叉樹
二叉樹是一種比順序結構更加高效的查找目標元素的結構,它可以從第一個父節點開始跟目標元素值比較,如果相等則返回當前節點,如果目標元素小於當前節點,則移動到左側子節點進行比較,
大於的情況則移動到右側子節點進行比較,反復進行操作最終移動到目標元素節點的位置
二叉樹缺點:
在大部分情況下,我們設計索引時,都會在表中提供一個自增索引字段作為建立索引的列,這種情況下所有的只能增節點都會添加到上一節點的右側,
這種情況下查詢節點時跟沒有添加索引的情況是一樣的。
2. 紅黑樹
紅黑樹也叫平衡二叉樹,它繼承了平衡二叉樹的優點,同時也解決了上面二叉樹自增整形索引的問題,從下面的動態圖可以看出紅黑樹會不斷對樹結構進行調整
紅黑樹的缺點:
在數據量大的時候,樹的高度也很大,從圖中可以看出每個節點只能有兩個子節點,所以紅黑樹的高度會達到幾十以上,增加了磁盤的I/O,降低了查找的效率。
3. HASH
對數據進行Hash散列運算,通過Hash算法計算hash值,再根據hash值從索引文件中獲取文件在磁盤的位置並讀取,快速定位目標記錄,查詢效率高。
缺點:
無法解決范圍查詢的場景、也不支持模糊查詢。
4. B-Tree
既然紅黑樹存在缺點,那么我們可以在紅黑樹的基礎之上構造一種新的存儲結構,解決思路:因為樹的高度太大,就只需要適當的增加每個樹節點可以存儲的數據個數即可,
但是數據個數也需要有一個閾值,否則會導致一個節點的數據過多導致其他的問題。
先來了解一下B-Tree的知識點
度(degree)-節點的數據存儲個數,每個樹節點中數據的個數大於15/16 * degree時會自動分裂,調整結構。
葉節點具有相同的深度
葉子節點的指針為空
節點中的數據key從左到右遞增排列
1. 樹節點結構:
在這里需要說明下的是,BTree的結構里每個節點包含了索引值和表記錄的信息,我們可以按照Map集合這樣理解:key=索引,value=表記錄,如下圖所示:
2. 優點:
BTree的結構可以彌補紅黑樹的缺點,解決數據量過大時整棵樹高度過大的問題,相同的數據量只需要更少的層,相同的深度可以存儲更多的數據,查找效率更高。
3. 缺點
在查詢單條數據是很快的,但是如果范圍查詢的話,BTree結構每次都需要從根節點查詢一遍,會影響效率,因此在實際應用時采用的是B+Tree
5. B+Tree(MySQL索引的真正存儲結構)
在介紹B+Tree之前,我們先來看下面兩個問題:
1. 為什么要對BTree繼續做優化?
要解答這個疑問需要先了解BTree每個節點結構(上面已經說明)和MySQL數據庫它是如何讀取索引數據的,索引和表數據在不使用的時候是存儲在文件中的,也就是磁盤,
當我們執行查詢操作時DBMS(數據庫管理系統)首先會先從內存中查找,如果找到直接使用,如果找不到則從磁盤文件中讀取;操作系統儲存數據的最小單位是頁(page),
一頁假設是4K大小(由操作系統決定),對內存和磁盤讀取數據是按一頁的整數倍讀取的。
這里我們假設數據庫一次IO操作就讀取1頁4K的數據,再假設圖中圈起來的元素就是一個大節點,內含多個小節點的索引和數據,其大小是10MB,
那么我們要從磁盤中讀取完整個大節點需要進行 10M / 4K = 2500次IO操作,這樣就可以看出如果大節點數據總量越大,需要執行的IO操作越多,花費的時間也越長,
因此為了提高性能,數據庫會建議我們一個大節點只存儲一頁4K大小的數據,這里的數據包含了索引和表記錄,另外我們還能計算出樹的度Degree應該設置成多大才合理:
Degree = 內存頁大小(4K) / 單個索引值字節大小;
進一步分析,索引值的大小相對於整條記錄的大小是很小的,如果我們需要查找的數據剛好是在最后,那么前面遍歷過的節點中存儲的記錄數據是不是對我們來說是沒用的,
它會占用比索引大得多的空間,導致我們一個大節點里能遍歷的索引數量大大減少,需要向下繼續遍歷的幾率就更大,花費更多時間查找,那么有沒有辦法可以優化呢?看下一個問題。
2. 相對於BTree,B+Tree做了哪些優化?
B+Tree存儲結構,只有葉子節點存儲數據
新的B+樹結構沒有在所有的節點里存儲記錄數據,而是只在最下層的葉子節點存儲,上層的所有非葉子節點只存放索引信息,
這樣的結構可以讓單個節點存放下更多索引值,增大度Degree的值,提高命中目標記錄的幾率。
這種結構會在上層非葉子節點存儲一部分冗余數據,但是這樣的缺點都是可以容忍的,因為冗余的都是索引數據,不會對內存造成大的負擔。
B+Tree特性:
非葉子節點不存儲data,只存儲key(索引值),可增大度
葉子節點不存儲指針
順序訪問指針,提高區間訪問的性能
每個葉子節點都指向下一個葉子節點
這點優化有什么用呢?我們直接看下面的B+Tree結構,如果我們進行范圍查找where id > 4的記錄,我們只需要先找到id = 4的記錄后自然就能通過葉子節點間的雙向指針方便地查詢出大於4的所有記錄。
三. 聯合索引底層存儲結構
單列索引其實也可以看做聯合索引,索引列為1的聯合索引,從下圖就可以看出聯合索引的底層存儲跟單列索引時類似的,區別在於聯合索引是每個樹節點中包含多個索引值,
在通過索引查找記錄時,會先將聯合索引中第一個索引列與節點中第一個索引值進行匹配,匹配成功接着匹配第二個索引列和索引值,直到聯合索引的所有索引列都匹配完;
如果過程中出現某一個索引列與節點相應位置的索引值不匹配的情況,則無需再匹配節點中剩余索引列,前往下一個節點。