Mysql InnoDB索引原理

Mysql InnoDB索引原理

9b90a7872fcd962d04017237dbabc5aa

索引這個概念說出來好像大家都知道,但是又有多少人能說出個所以然來呢?
本文的目的希望讓讀者能夠掌握索引的基本概念,做到知其然也知其所以然,接下來筆者將從以下兩個角度爲你闡述Mysql索引

何爲索引
使用索引的正確姿勢

Mysql索引是什麼

A data structure that provides a fast lookup capability for rows of a table, typically by forming a tree structure (B-tree) representing all the values of a particular column or set of columns.
—引用自mysql官方文檔

簡單來說索引是一種數據結構(通常是樹結構B-tree),這個數據結構中存放着特定的列或列集,以提供快速的查找功能。
舉一個例子來幫助大家理解,圖書的目錄,目錄即索引,讀者根據你想要查看的內容(索引),從目錄中找到對應的頁碼(數據指針),定位到最終內容。

索引類型

Mysql的索引由儲存引擎實現,不同的儲存引擎支持的索引可能會不一樣,本文只講解最常見的索引類型B-Tree索引(這裏的B是Balance的縮寫)。

B+Tree

圖1-1 建立在B-Tree結構(從技術上來說是B+Tree)上的索引

B-Tree由根節點(圖中未畫出)、普通節點和葉子節點構成,普通節點存放指向下一節點的指針,具體指向數據的指針則存放在葉子結點中(所有葉子結點都在最後一層)。

B-Tree索引之所以能夠加快數據的訪問速度,是因爲在查找數據時不需要去一行行的查找並比較數據(全表掃描),而是從樹的根節點開始比較查找,根據要查找的值一級一級的去比較節點頁的值拿到下級指針(定義了子節點中值的上限和下限),最終找到索引所在的葉子頁並拿到數據指針。

聚簇索引

實際上不是一種索引類型,其本質就是B-Tree索引,區別在於其葉子節點的存放的數據,葉子節點將不會存放指向數據的指針,而是直接存放數據行即每個葉子節點就是一行數據,即聚簇索引是InnoDB真正儲存數據的地方。

InnoDB通過主鍵來聚集數據,默認聚簇索引索引的列爲主鍵,如果沒有定義主鍵,InnoDB會選擇一個默認的非空索引代替,如果沒有這樣的索引,InnoDB會隱式的定義一個主鍵作爲聚簇索引。

二級索引

可以理解爲普通的B-Tree索引,非聚簇索引,這裏唯一要明確的一點是二級索引葉子節點中儲存的“行指針”其本質是主鍵,即聚簇索引中的鍵。所以當使用二級索引查詢時需要進行二次查詢,先從二級索引獲取主鍵,再使用主鍵從聚簇索引中獲取數據行(這裏排除覆蓋索引的情況)。

簡單的例子

看了上面的聚簇索引和二級索引,相信很多讀者還是存在一定的認知模糊,下面通過一個《高性能Mysql》中關於InnoDB數據分佈的例子來幫助大家,更好的認識聚簇索引和二級索引究竟如何工作。

下面是這個例子的表結構,layout_test表中有兩個int類型字段,其中col1列作爲主鍵,同時爲col2列生成普通索引。

CREATE TABLE layout_test (
	col1 int NOT NULL,
	col2 int NOT NULL,
	PRIMARY KEY(col1),
	KEY(col2)
);

layout_test表的聚簇索引部分

2b700d4ca4b4b6c62d65a1798bdee670

圖1-2 表layout_test的聚簇索引

簡單講解一下上圖:

1.首先大家可以先忽略其中的事務ID和回滾指針,因爲這和理解索引部分暫時沒有關係,有興趣的讀者可以另行了解。

2.上圖只是包含了聚簇索引的葉子節點部分,可以看到葉子節點中並沒有儲存數據指針,而是儲存了主鍵col1和剩下的列col2,即每一個葉子節點我們可以理解成一條數據記錄。比如第一個節點:主鍵列col1值爲3、剩餘列col2值爲93其包含了這條記錄的所有數據。

3.這裏我想吐槽一下這個例子,其實蠻容易讓人誤解的,如果再新增一個col3列的話,其實能更方便的將聚簇索引和二級索引區分開來,這裏我們假設有col3,那麼上圖的每個葉子節點都將多一個col3列的值。

**layout_test表的二級索引col2**

5e498ea3b5eef0596f54f66460a050d5

圖1-3 表layout_test的col2列索引

1.圖1-3很簡單也很好理解,這裏簡單說明一下,二級索引中每個葉子節點存放了兩種數據,分別是索引鍵即col2,和主鍵col1。上圖最後一個葉子節點:93是col2的值,3則是主鍵col1。

2.這裏還是跟上面一樣,如果表layout_test還有個col3列,上圖不會有任何的變化,二級索引每個葉子節點只會存儲索引鍵和主鍵。

藉助上面的例子,用兩個分別以col1和col2字段作爲查詢條件的SQL,爲大家演示InnoDB的聚簇索引是如何工作的。

#以col1作爲查詢條件
SELECT col1, col2, col3 FROM layout_test WHERE col1 = 3;

#以col2作爲查詢條件
SELECT col1, col2, col3 FROM layout_test WHERE col2 = 93;

爲了防止“覆蓋索引”讓大家引起歧義,這裏假設還有一個col3字段

**第一條SQL執行:**根據主鍵col1 = 3,查詢引擎會直接在聚簇索引中找到鍵爲3的葉子節點。即圖1-2的第一個葉子節點,其中包含了鍵col1,和剩餘的字段col2和col3。

**第二條SQL執行:**根據主鍵col2 = 93,查詢引擎會從二級索引中查找鍵爲93的葉子節點。即圖1-3中的最後一個葉子節點,從中拿到主鍵3,然後再根據主鍵從聚簇索引中查找。即二次查詢。(這裏解釋一下爲什麼需要假設一個字段col3,因爲如果只有兩個字段的話,其實只要查一次二級索引就可以拿到所有數據了,二級索引中已經包含了鍵col2和主鍵col1,這就是覆蓋索引可以加速查詢的道理,因爲不需要再去查一遍聚簇索引,性能自然高)


寫在最後

索引這個概念,細講可能花一本書版本都講不完,如何正確使用索引就留在下一篇跟大家分享。這裏只是很粗淺的跟大家介紹了關於InnoDB索引的概念,目的是讓不熟悉索引這塊知識的讀者,對其有個大體的概念。對於有興趣深入瞭解的讀者,強烈推薦《高性能Mysql》這本書,本文的大多數觀點也是來源於此。
礙於筆者所學有限,本文如有表述不當處歡迎於留言中指出。

參考材料
1.《高性能Mysql》
2. [mysql開發手冊](https://dev.mysql.com/doc/

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