深刻淺出Mysql索引

索引的出現其實就是爲了提升數據查詢的效率,就像書的目錄同樣。mysql

索引模型有三種常見、也比較簡單的數據結構分別是哈希表、有序數組和搜索樹。sql

哈希表數據庫

哈希表是一種以鍵 - 值(key-value)存儲數據的結構,咱們只要輸入待查找的值即 key,就能夠找到其對應的值即 Value。哈希的思路很簡單,把值放在數組裏,用一個哈希函數把 key 換算成一個肯定的位置,而後把 value 放在數組的這個位置。數組

 

 適用於只有等值查詢的場景,好比 Memcached 及其餘一些NoSQL 引擎。性能優化

 

有序數組數據結構

有序數組在等值查詢和範圍查詢場景中的性能就都很是優秀。函數

 

這裏咱們假設身份證號沒有重複,這個數組就是按照身份證號遞增的順序保存的。這時候若是你要查 ID_card_n2 對應的名字,用二分法就能夠快速獲得,這個時間複雜度是O(log(N))。性能

若是僅僅看查詢效率,有序數組就是最好的數據結構了。可是,在須要更新數據的時候就麻煩了,你往中間插入一個記錄就必須得挪動後面全部的記錄,成本過高。因此,有序數組索引只適用於靜態存儲引擎,好比你要保存的是 2017 年某個城市的全部人口信息,這類不會再修改的數據。優化

 

二叉搜索樹spa

二叉搜索樹的時間複雜度是 O(log(N))。樹能夠有二叉,也能夠有多叉。多叉樹就是每一個節點有多個兒子,兒子之間的大小保證從左到右遞增。二叉樹是搜索效率最高的,可是實際上大多數的數據庫存儲卻並不使用二叉樹。其緣由是,索引不止存在內存中,還要寫到磁盤上。

爲了讓一個查詢儘可能少地讀磁盤,就必須讓查詢過程訪問儘可能少的數據塊。那麼,咱們就不該該使用二叉樹,而是要使用「N 叉」樹。這裏,「N 叉」樹中的「N」取決於數據塊的大小。

 

InnoDB 的索引模型

在 InnoDB 中,表都是根據主鍵順序以索引的形式存放的,這種存儲方式的表稱爲索引組織表。

每個索引在 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),兩棵樹的示例示意圖以下。

主鍵索引的葉子節點存的是整行數據。在 InnoDB 裏,主鍵索引也被稱爲聚簇索引(clustered index)。

非主鍵索引的葉子節點內容是主鍵的值。在 InnoDB 裏,非主鍵索引也被稱爲二級索引(secondary index)。

根據上面的索引結構說明,咱們來討論一個問題:基於主鍵索引和普通索引的查詢有什麼區別?

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

也就是說,基於非主鍵索引的查詢須要多掃描一棵索引樹。所以,咱們在應用中應該儘可能使用主鍵查詢。

 

爲何主鍵須要自增呢?

這樣每次插入一條新記錄,都是追加操做,都不涉及到挪動其餘記錄,也不會觸發葉子節點的分裂,性能高得多。

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

因此,從性能和存儲空間方面考量,自增主鍵每每是更合理的選擇。

 

最左前綴原則

因爲覆蓋索引能夠減小樹的搜索次數,顯著提高查詢性能,減小回表,因此使用覆蓋索引是一個經常使用的性能優化手段。

在創建聯合索引的時候,如何安排索引內的字段順序?

第一原則是,若是經過調整順序,能夠少維護一個索引,那麼這個順序每每就是須要優先考慮採用的。

,若是既有聯合查詢,又有基於 a、b 各自的查詢呢?查詢條件裏面只有 b 的語句,是沒法使用 (a,b) 這個聯合索引的,這時候你不得不維護另一個索引,也就是說你須要同時維護 (a,b)、(b) 這兩個索引。

這時候,咱們要考慮的原則就是空間了。好比上面這個市民表的狀況,name 字段是比 age 字段大的 ,那我就建議你建立一個(name,age) 的聯合索引和一個 (age) 的單字段索引。

 

索引下推

若是如今有一個需求:檢索出表中「名字第一個字是張,並且年齡是 10 歲的全部男孩」。那麼,SQL 語句是這麼寫的:

mysql> select * from tuser where name like '張 %' and age=10 and ismale=1;

MySQL 5.6 以前,只能從 ID3 開始一個個回表。到主鍵索引上找出數據行,再對比字段值。

而 MySQL 5.6 引入的索引下推優化(index condition pushdown), 能夠在索引遍歷過程當中,對索引中包含的字段先作判斷,直接過濾掉不知足條件的記錄,減小回表次數,以下圖所示:

相關文章
相關標籤/搜索