首先我們來明確一下索引的定義:
索引是幫助MySQL高效獲取數據的排好序的數據結構。
索引一般分爲四大類:
FULLTEXT:全文索引
NORMAL:普通索引
SPATIAL :組合索引
UNIQUE :唯一索引(主鍵索引也是唯一索引的一種)
既然索引是數據結構,那麼他究竟採用的是什麼數據結構啦。
一般MySQL採用的Hash,B+tree兩種數據結構,一般使用B+Tree的索引佔據98%以上。
Hash索引通過哈希函數,獲取磁盤的物理位置,快速的獲取數據。
Hash索引的優點 :在查詢單個數據的時候執行效率非常高。
缺點:在執行範圍查詢的時候效率低下。
B+Tree是(B-Tree的變種),以下是B+tree的特性
1、非葉子節點不存儲data,只存儲索引,可以放更多的索引
2、葉子節點不存儲指針
3、順序訪問指針,提高區間訪問性能
下面圖形展示了B+Tree的一個結構
B+Tree中的每一層默認最多存儲16個字節的數據。
下面我們來講一下聚集索引和非聚集索引的區別
聚集索引 以InnoDB作爲存儲引擎的表,表中的數據都會有一個主鍵,即使你沒有創建組件,MYSQL會自動幫你創建一個隱式主鍵。這種以主鍵作爲索引值,葉子節點包含所有元素的B+ Tree索引稱之爲聚集索引。
非聚集索引:非聚集索引與聚集索引的區別在於非聚集索引的葉子節點不存儲表中的數據,而是存儲該列對應的主鍵,想要查找數據我們還需要根據主鍵再去聚集索引中進行查找,這個再根據聚集索引查找數據的過程,我們稱爲回表。
下面我們就分別講解一下聚集索引和非聚集索引的查找過程。
利用聚集索引查找數據的過程
以上B+tree就是典型的聚集索引存儲。
現在假設我們需要查找id>=18且id<40的用戶數據。以下爲對應的SQL語句。
select * from user where id>=18 and id <40 |
其中id爲主鍵,查找過程如下
1、一般根節點都是常駐內存的,也就是說頁1已經在內存中,我們直接在在內存中讀取到頁1的數據,找出id>=18 and id <40的數據。我們首先找到id=18的鍵值。根據指針,定位到頁3。
2、根據頁1中的p2指針去從磁盤中將頁3的數據加載到內存中,然後從頁3中查找id>=18 and id <40,我們首頁定位到id=18,此時根據頁3中的p1指針定位到頁8。
3、根據定位將頁8的數據從磁盤加載到內存中,並將所有數據與條件id>=18 and id <40,發現頁8中的所有數據均滿足此條件,根據頁8的指針,定位到頁9.
4、根據定位將頁9的數據從磁盤加載到內存中,並將所有數據與條件id>=18 and id <40,發現頁8中的所有數據均滿足此條件,根據頁10的指針,定位到頁10.
5、以此類推知道查找到12頁,發現41大於40不滿足條件,終止查找。將滿足條件的數據從內存中返回。
利用非聚集索引查找數據
這個非聚集索引表示的是用戶幸運數字的索引,表結構如下
在葉子節點中,不再存儲所有的數據了,存儲的是鍵值和主鍵。對於葉子節點中的 x-y,比如 1-1。左邊的 1 表示的是索引的鍵值,右邊的 1 表示的是主鍵值。
查找過程:
1、在頁1中找到luckyNum等於18,找到luckyNum=18,通過頁1中p2指針定位到頁3,。
2、將頁3的數據加載到內存中,比較找到luckyNum=31,通過頁3中的p3指針定位到頁10.
3、將頁3的數據加載到內存中,比較找到luckyNum=33,獲取數據。找到主鍵值47。再根據主鍵值,走一遍聚集索引的查找流程。
根據數據庫存儲結構,總結如下優化技巧:
1、儘量使用int自增類型作爲主鍵,佔用存儲空間較小,搜索時比較成功較小。若字符串爲主鍵,增加索引文件大小,切構建索引時,利用索引查詢時耗時較長。
2、遵循最左前綴匹配原則
儘量構建組合索引,如存在(a,b,c)三個字段的組合索引,則沒有必要單獨構建(a)。查詢從索引的最左列開始並且不跳過索引中的列。
3、儘量不要where條件中構建了索引的字段上做任何操作(計算,函數,or,類型轉換,like ),否則會使索引失效,進行全表掃描。
4、選擇唯一性高的字段建立索引(字段中的所以元素都是唯一的)