MySQL技術總結第二篇

此篇着重講MySQL存儲引擎中的索引和算法

寫在前面:

數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。如果索引太多,應用程序性能就會受影響,如果索引太少,查詢性能又會受影響。所以找到平衡點至關重要。

InnoDB存儲引擎支持以下索引:
B+樹索引
哈希索引

其中InnoDB的哈希索引是自適應的,即自動爲表生成哈希索引。InnoDB存儲引擎會監控對錶上各索引頁的查詢。如果觀察到建立哈希索引可以帶來速度提升,則建立哈希索引,稱之爲自適應哈希索引(Adaptive Hash Index, AHI)。AHI是通過緩衝池的B+樹頁構造而來,因此建立的速度很快,而且不需要對整張表構建哈希索引。InnoDB存儲引擎會自動根據訪問的頻率和模式來自動地爲某些熱點頁建立哈希索引。

 

一,數據結構與算法

如何在索引中快速查詢到數據呢?一般的存儲引擎底層都用了樹結構,提起樹的查找效率,那就要從二分查找法說起。
二分查找法

int l;
int r;
while(l < r){
int mid = l + (r-l)/2;
if(query1)
r = m;
else
l = m+1;
}

通過二分查找,樹可以做到查找數據時間爲O(logN),關於樹結構在此不再贅述,可以參考數據結構之樹

二,B+樹與B+樹索引

B+樹是爲磁盤或其他直接存取輔助設備設計的一種多路平衡查找樹。在B+樹中,所有記錄節點都是按鍵值大小順序放在同一層的葉子節點上,由各葉子節點指針進行連接。非葉節點不存儲實際值,只存儲指針。
B+樹索引高度一般在2-4層,即查找某一鍵值的行記錄最多需要2-4次。

數據庫B+樹索引可分爲聚集索引(InnoDB)和輔助索引(MyISAM)。

聚集索引

聚集索引一般是表中的主鍵索引,如果表中沒有顯示指定主鍵,則會選擇表中的第一個不允許爲NULL的唯一索引,如果還是沒有的話,就採用Innodb存儲引擎爲每行數據內置的6字節ROWID作爲聚集索引。

InnoDB存儲引擎表是索引組織表,即表中數據按照主鍵順序存放。而聚集索引就是按照每張表的主鍵構造一顆B+樹,同時葉子節點中存放的即爲整張表的行記錄數據,所以聚集索引的葉節點也叫做數據頁。每個數據頁通過一個雙向鏈表連接,按照主鍵順序排序,由於通過雙向鏈表可維護,物理存儲上可以同樣不按照主鍵存儲。
聚集索引的另一個好處是,對於主鍵的排序查找和範圍查找速度很快,葉子節點的數據就是用戶所要查詢的數據,範圍查詢只要查找主鍵某一範圍的數據,通過也足節點上層中間節點就可得到頁的範圍,之後讀取數據頁。

輔助索引

輔助索引(非聚集索引)(secondary index)葉子節點不包含行記錄的全部數據。葉子節點除了包含鍵值以外,每個葉子節點的索引中還包含書籤,用來確定InnoDB中索引對應的行數據。其中據說堆表比索引組織表要快,所以對於頻繁更新列和索引,推薦使用輔助索引。同樣對於大數目的不同值,InnoDB不建議使用過長的字段作爲主鍵,因爲所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。

聚集索引和輔助索引不同的是葉子節點存放的是否是一整行的信息。

三,哈希算法與哈希索引

哈希算法是一種常見算法,時間複雜度爲O(1)。
InnoDB存儲引擎使用哈希算法來對字典進行查找,衝突機制採用鏈表方式。Hash 索引結構的特殊性,其檢索效率非常高,索引的檢索可以一次定位,不像B-Tree 索引需要從根節點到枝節點,最後才能訪問到頁節點這樣多次的IO訪問,所以 Hash 索引的查詢效率要遠高於 B-Tree 索引。

雖然 Hash 索引效率高,但是 Hash 索引本身由於其特殊性也帶來了很多限制和弊端,主要有以下這些:

(1)Hash 索引僅僅能滿足"=",和"<=>"等值查詢,不能使用範圍查詢。
如果是等值查詢,那麼哈希索引明顯有絕對優勢,因爲只需要經過一次算法即可找到相應的鍵值;當然了,這個前提是,鍵值都是唯一的。如果鍵值不是唯一的,就需要先找到該鍵所在位置,然後再根據鏈表往後掃描,直到找到相應的數據;由於 Hash 索引比較的是進行 Hash 運算之後的 Hash 值,所以它只能用於等值的過濾,不能用於基於範圍的過濾,因爲經過相應的 Hash 算法處理之後的 Hash 值的大小關係,並不能保證和Hash運算前完全一樣。

(2)Hash 索引無法被用來避免數據的排序操作。
由於 Hash 索引中存放的是經過 Hash 計算之後的 Hash 值,而且Hash值的大小關係並不一定和 Hash 運算前的鍵值完全一樣,所以數據庫無法利用索引的數據來避免任何排序運算;

(3)Hash 索引不支持多列聯合索引的最左匹配規則;
對於組合索引,Hash 索引在計算 Hash 值的時候是組合索引鍵合併後再一起計算 Hash 值,而不是單獨計算 Hash 值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也無法被利用。

(4)Hash 索引在任何時候都不能避免表掃描。
前面已經知道,Hash 索引是將索引鍵通過 Hash 運算之後,將 Hash運算結果的 Hash 值和所對應的行指針信息存放於一個 Hash 表中,由於不同索引鍵存在相同 Hash 值,所以即使取滿足某個 Hash 鍵值的數據的記錄條數,也無法從 Hash 索引中直接完成查詢,還是要通過訪問表中的實際數據進行相應的比較,並得到相應的結果。

(5)B+樹索引的關鍵字檢索效率比較平均,不像B樹那樣波動幅度大,在有大量重複鍵值情況下,哈希索引的效率也是極低的,因爲存在所謂的哈希碰撞問題

備註:複合索引

用戶可以在多個列上建立索引,這種索引叫做複合索引(組合索引);     複合索引在數據庫操作期間所需的開銷更小,可以代替多個單一索引,mysql在按照最左前綴的索引匹配原則,且會自動優化 where 條件的順序。

例子:

創建索引     create index idx1 on table1(col1,col2,col3)      查詢     select * from table1 where col1= A and col2= B and col3 = C     這時候查詢優化器,不在掃描表了,而是直接的從索引中拿數據,因爲索引中有這些數據,這叫覆蓋式查詢,這樣的查詢速度非常快; 

對於複合索引,在查詢使用時,最好將條件順序按找索引的順序,這樣效率最高;     select * from table1 where col1=A AND col2=B 可以     如果使用 where col3=B AND col1=A 或者 where col2=B 將不會使用索引.

當條件中只有 col2=B AND col1=A 時,會自動轉化爲 col1=A AND col2=B,所以依然會使用索引。

下麪條件將能用上部分組合索引查詢:

  • A>5 AND B=2 ——當範圍查詢使用第一列,查詢條件僅僅能使用第一列
  • A=5 AND B>6 AND C=2 ——範圍查詢使用第二列,查詢條件僅僅能使用前二列
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章