MySQL存儲引擎MyISAM和InnoDB,索引結構優缺點

MySQL存儲引擎MyISAM和InnoDB底層索引結構算法

深刻理解MySQL索引底層數據結構與算法 (各類索引結構優缺點)數據庫

Myisam和Innodb索引實現的不一樣(存儲結構)數據結構

存儲引擎做用於什麼對象

存儲引擎是做用在表上的,而不是數據庫。優化

MyISAM和InnoDB對索引和數據的存儲在磁盤上是如何體現的

先來看下面建立的兩張表信息,role表使用的存儲引擎是MyISAM,而user使用的是InnoDB:spa

再來看下兩張表在磁盤中的索引文件和數據文件:.net

1. role表有三個文件,對應以下:設計

role.frm:表結構文件
role.MYD:數據文件(MyISAM Data)
role.MYI:索引文件(MyISAM Index)指針


2. user表有兩個文件,對應以下:對象

user.frm:表結構文件
user.ibd:索引和數據文件(InnoDB Data)
也因爲兩種引擎對索引和數據的存儲方式的不一樣,咱們也稱MyISAM的索引爲非彙集索引,InnoDB的索引爲彙集索引。blog

InnoDB 索引文件和數據文件是一個;MyISAM索引文件和數據文件是分開的。

MyISAM主鍵索引與輔助索引的結構

咱們先列舉一部分數據出來分析,以下:

上面已經說明了MyISAM引擎的索引文件和數據文件是分離的,咱們接着看一下下面兩種索引結構異同。

主鍵索引

上一篇文章已經介紹過數據庫索引是採用B+Tree存儲,而且只在葉子節點存儲數據,在MyISAM引擎中葉子結點存儲的數據實際上是索引和數據的文件指針兩類。

以下圖中咱們以Col1列做爲主鍵創建索引,對應的葉子結點儲存形式能夠看一下表格。

過索引查找數據的流程:先從索引文件中查找到索引節點,從中拿到數據的文件指針,再到數據文件中經過文件指針定位了具體的數據。

輔助(非主鍵)索引

以Col2列創建索引,獲得的輔助索引結構跟上面的主鍵索引的結構是相同的。

在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是惟一的,而輔助索引的key能夠重複。

InnoDB主鍵索引與輔助索引的結構

雖然InnoDB也使用B+Tree做爲索引結構,但具體實現方式卻與MyISAM大相徑庭。

第一個重大區別是InnoDB的數據文件自己就是索引文件。從上文知道,MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地 址。而在InnoDB中,表數據文件自己就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據 表的主鍵,所以InnoDB表數據文件自己就是主索引。

主鍵索引

咱們已經知道InnoDB索引是彙集索引,它的索引和數據是存入同一個.idb文件中的,所以它的索引結構是在同一個樹節點中同時存放索引和數據,以下圖中最底層的葉子節點有三行數據,對應於數據表中的Col一、Col二、Col3數據項。

上圖是InnoDB主索引(同時也是數據文件)的示意圖,能夠看到葉節點包含了完整的數據記錄。這種索引叫作彙集索引。由於InnoDB的數據文件自己要按主鍵彙集,因此InnoDB要求表必須有主鍵(MyISAM能夠沒有),若是沒有顯式指定,則MySQL系統會自動選擇一個能夠惟一標識數據記錄的列做爲主鍵,若是不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段做爲主鍵,這個字段長度爲6個字節,類型爲長整形。

輔助(非主鍵)索引

第二個與MyISAM索引的不一樣是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的全部輔助索引都引用主鍵做爲data域。下圖爲定義在Col3上的一個輔助索引:

在最底層的葉子結點有兩行數據,第一行的字符串是輔助索引,按照ASCII碼進行排序,第二行的整數是主鍵的值。

這裏以英文字符的ASCII碼做爲比較準則。彙集索引這種實現方式使得按主鍵的搜索十分高效,可是輔助索引搜索須要檢索兩遍索引:首先檢索輔助索引得到主鍵,而後用主鍵到主索引中檢索得到記錄。

InnoDB索引結構須要注意的點

1. 數據文件自己就是索引文件

2. 表數據文件自己就是按B+Tree組織的一個索引結構文件

3. 彙集索引中葉節點包含了完整的數據記錄

4. InnoDB表必需要有主鍵,而且推薦使用整型自增主鍵

正如咱們上面介紹InnoDB存儲結構,索引與數據是共同存儲的,不論是主鍵索引仍是輔助索引,在查找時都是經過先查找到索引節點才能拿到相對應的數據,若是咱們在設計表結構時沒有顯式指定索引列的話,MySQL會從表中選擇數據不重複的列創建索引,若是沒有符合的列,則MySQL自動爲InnoDB表生成一個隱含字段做爲主鍵,而且這個字段長度爲6個字節,類型爲整型。

 

那爲何推薦使用整型自增主鍵而不是選擇UUID?

UUID是字符串,比整型消耗更多的存儲空間;
在B+樹中進行查找時須要跟通過的節點值比較大小,整型數據的比較運算比字符串更快速;
自增的整型索引在磁盤中會連續存儲,在讀取一頁數據時也是連續;UUID是隨機產生的,讀取的上下兩行數據存儲是分散的,不適合執行where id > 5 && id < 20的條件查詢語句。
在插入或刪除數據時,整型自增主鍵會在葉子結點的末尾創建新的葉子節點,不會破壞左側子樹的結構;UUID主鍵很容易出現這樣的狀況,B+樹爲了維持自身的特性,有可能會進行結構的重構,消耗更多的時間。

爲何非主鍵索引結構葉子節點存儲的是主鍵值?

保證數據一致性和節省存儲空間,能夠這麼理解:商城系統訂單表會存儲一個用戶ID做爲關聯外鍵,而不推薦存儲完整的用戶信息,由於當咱們用戶表中的信息(真是名稱、手機號、收貨地址···)修改後,不須要再次維護訂單表的用戶數據,同時也節省了存儲空間。

總結

瞭解不一樣存儲引擎的索引實現方式對於正確使用和優化索引都很是有幫助,例如知道了InnoDB的索引實現後,就很容易明白爲何不建議使用過長 的字段做爲主鍵,由於全部輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如,用非單調的字段做爲主鍵在InnoDB中不是個好主意,由於 InnoDB數據文件自己是一顆B+Tree,非單調的主鍵會形成在插入新記錄時數據文件爲了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用 自增字段做爲主鍵則是一個很好的選擇。

相關文章
相關標籤/搜索