深入淺出索引

深入淺出索引

本文是在看極客時間《Mysql實戰45講》時記的筆記,整理下加深理解。

簡單來說,數據庫索引就是爲了提高數據庫查詢的效率,就像書的目錄一樣,可以根據目錄快速的找到其中的某一個知識點。

索引模型

  • 哈希表
  • 有序數組
  • 搜索樹

簡單的介紹下以上三種模型:

==哈希表==是一種以鍵-值(key-value)存儲的數據結構,我們只要輸入待查找的key值,就可以找到其對應的值value,哈希的思路很簡單,把值放在數組裏,通過一個哈希函數把key換算成一個確定的位置,然後把value放在數組的這個位置。不可避免的情況下,多個Key值經過哈希運算會出現同一個值的情況,處理這種情況的一種方法是拉出一個鏈表。

由於哈希表內部的排序並不是遞增的,所以新增元素的時候速度會很快,但缺點是因爲不是有序的,所以哈希表做區間查詢的速度是很慢的。所以,哈希表這種結構只適用於只有等值查詢的場景,比如Memcached以及其他Nosql引擎。

==有序數組==在等值查詢和範圍查詢場景中的性能都非常優秀。但是在需要更新數據的時候就很麻煩了,如果在中間插入一個記錄就必須挪動後面所有的記錄,成本太高。所以有序數組只適用於靜態存儲引擎。

N叉樹在讀寫上的性能優點,以及適配磁盤的訪問模式,已經被廣泛應用於數據庫引擎中了。

不管是哈希還是有序數組,或者 N 叉樹,它們都是不斷迭代、不斷優化的產物或者解決方案。在我們心裏要有個概念,數據庫底層存儲的核心就是基於這些數據模型的,每碰到一個新的數據庫,我們都應先關注他的數據模型,這樣才能從理論上分析出這個數據庫的應用場景。

InnoDB的索引模型

在InnoDB中,表都是根據主鍵順序以索引的形式存放的,這種存儲方式的表稱爲索引組織表。InnoDB使用了B+樹索引模型,所以數據都是存儲在B+樹中的。

每一個索引在InnoDB裏面都對應一顆B+樹。

假設我們有一個主鍵列爲ID的表,表中有字段K,並在K上有索引。

這個表的建表語句:

mysql> create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;

表中 R1~R5 的 (ID,k) 值分別爲 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),兩棵樹的示意圖如下:

圖片描述

從圖中我們可以看出來,根據葉子節點的內容,索引分爲主鍵索引和非主鍵索引。

主鍵索引的葉子節點存放的是整行的數據,非主鍵索引的葉子節點存放的是主鍵的值。

根據上面的索引結構說明,我們可以得出一個問題,基於主鍵索引和普通索引的查詢區別:

  • 如果語句是select * from T where ID = 500;,即主鍵查詢方式,則只需要搜索ID這顆B+樹;
  • 如果語句是select * from T where k = 5;,即普通索引查詢方式,則需要先搜索k索引樹,得到ID的值爲500,再到ID索引樹搜索一次,這個過程稱爲回表。

也就是說基於非主鍵索引查詢會多掃描一次索引樹。

索引維護

B+樹爲了維護索引的有序性,在插入新值的時候需要做必要的維護。

建表時,儘量保持有自增主鍵。每次插入一條新記錄,都是追加操作,都不涉及到挪動其他記錄,也不會觸發葉子節點的分裂。

而有業務邏輯的字段做主鍵,則往往不容易保證有序插入。

同時主鍵的長度越小,普通索引的葉子節點就越小,普通索引佔用的空間就越小。

所以從性能和存儲空間來看,自增主鍵往往是更合理的選擇。

覆蓋索引

如果執行的語句是 select ID from T where k between 3 and 5,這時只需要查 ID 的值,而ID 的值已經在 k 索引樹上了,因此可以直接提供查詢結果,不需要回表。也就是說,在這個查詢裏面,索引 k 已經“覆蓋了”我們的查詢需求,我們稱爲覆蓋索引。

由於覆蓋索引可以減少樹的搜索次數,顯著提升查詢性能,所以使用覆蓋索引是常用的性能優化手段。

最左前綴原則

第一原則是,如果通過調整順序,可以少維護一個索引,那麼這個順序往往就是需要優先考慮採用的。

其次考慮的就是空間,比如name 字段是比 age 字段大的 ,那我就建議你創建一個(name,age) 的聯合索引和一個 (age) 的單字段索引。

索引下推

在Mysql5.6之前,只能從最左前綴查詢到ID開始一個個回表,到主鍵索引上找出數據行,再對比字段值。

Mysql5.6之後,引入索引下推的優化,可以在遍歷過程中,對索引中包含的字段先做判斷,直接過濾掉不滿足條件的記錄,減少回表次數。

總之在滿足語句需求的情況下,儘量地減少訪問資源是數據庫設計的重要原則之一。我們在使用數據庫的時候,尤其在設計表結構時,也要以減少資源消耗爲目標。

參考資料

極客時間《Mysql實戰45講》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章