本文是在看極客時間《Mysql實戰45講》時記的筆記,整理下加深理解。mysql
簡單來講,數據庫索引就是爲了提升數據庫查詢的效率,就像書的目錄同樣,能夠根據目錄快速的找到其中的某一個知識點。sql
簡單的介紹下以上三種模型:數據庫
==哈希表==是一種以鍵-值(key-value)存儲的數據結構,咱們只要輸入待查找的key值,就能夠找到其對應的值value,哈希的思路很簡單,把值放在數組裏,經過一個哈希函數把key換算成一個肯定的位置,而後把value放在數組的這個位置。不可避免的狀況下,多個Key值通過哈希運算會出現同一個值的狀況,處理這種狀況的一種方法是拉出一個鏈表。數組
因爲哈希表內部的排序並非遞增的,因此新增元素的時候速度會很快,但缺點是由於不是有序的,因此哈希表作區間查詢的速度是很慢的。因此,哈希表這種結構只適用於只有等值查詢的場景,好比Memcached以及其餘Nosql引擎。性能優化
==有序數組==在等值查詢和範圍查詢場景中的性能都很是優秀。可是在須要更新數據的時候就很麻煩了,若是在中間插入一個記錄就必須挪動後面全部的記錄,成本過高。因此有序數組只適用於靜態存儲引擎。數據結構
N叉樹在讀寫上的性能優勢,以及適配磁盤的訪問模式,已經被普遍應用於數據庫引擎中了。數據庫設計
不論是哈希仍是有序數組,或者 N 叉樹,它們都是不斷迭代、不斷優化的產物或者解決方案。在咱們內心要有個概念,數據庫底層存儲的核心就是基於這些數據模型的,每碰到一個新的數據庫,咱們都應先關注他的數據模型,這樣才能從理論上分析出這個數據庫的應用場景。函數
在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講》