MySQL——索引實現原理

在MySQL中,索引屬於存儲引擎級別的概念,不一樣存儲引擎對索引的實現方式是不一樣的,本文主要討論MyISAM和InnoDB兩個存儲引擎的索引實現方式。html

MyISAM索引實現

MyISAM引擎使用B+Tree做爲索引結構。mysql

MyISAM會按照數據插入的順序分配行號,從0開始,而後按照數據插入的順序存儲在磁盤上。由於行是定長的,因此能夠從表的開頭跳過相應的字節找到須要的行。算法

mark

MyISAM的一級索引(主鍵索引),一個節點包含多個內部節點,索引中的每一個葉子節點包含「行號」。假設咱們以col1爲主鍵,則下圖是一個MyISAM表的主索引(Primary key)示意。sql

mark

能夠看出MyISAM的索引文件僅僅保存數據記錄的行號,而後經過此行號回表查詢須要的數據。數據庫

那col2列上的索引(輔助索引)又會怎麼樣呢?有什麼特別之處嗎?答案是否認的,和一級索引(主鍵索引)沒有什麼區別。在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是惟一的,而輔助索引的key能夠重複。若是咱們在col2上創建一個輔助索引,則此索引的結構以下圖所示:數據結構

mark

所以,MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,則取出其data域的值,而後以data域的值爲地址,讀取相應數據記錄。MyISAM的索引方式索引和數據存放是分開的,非彙集」的,因此也叫作非彙集索引。性能

InnoDB索引實現

雖然InnoDB也使用B+Tree做爲索引結構,但具體實現方式卻與MyISAM大相徑庭。由於InnoDB支持聚簇索引(主鍵索引),聚簇索引就是表,因此InnoDB不用像MyISAM那樣須要獨立的行存儲。也就是說,InnoDB的數據文件自己就是索引文件。優化

聚簇索引的每個葉子節點都包含了主鍵值、事務ID、用於事務和MVCC的回滾指針以及全部的剩餘列。假設咱們以col1爲主鍵,則下圖是一個InnoDB表的聚簇索引(主鍵索引)(Primary key)示意。操作系統

mark

與MyISAM不一樣的是,InnoDB的二級索引和聚簇索引很不相同。InnoDB的二級索引的葉子節點存儲的不是行號(行指針),而是主鍵列。這種策略的缺點是二級索引須要兩次索引查找,第一次在二級索引中查找主鍵,第二次在聚簇索引中經過主鍵查找須要的數據行。設計

畫外音:能夠經過咱們前面提到過的索引覆蓋來避免回表查詢,這樣就只須要一次回表查詢,對於InnoDB而言,就是隻須要一次索引查找就能夠查詢到須要的數據記錄,由於須要的數據記錄已經被索引到二級索引中,直接就能夠找到。

好處是InnoDB在移動行時無需更新一級索引中的這個」指針「,由於主鍵是不會改變的,可是行指針卻會改變。

InnoDB的二級索引示意如圖:

mark

使用InnoDB主鍵應該知道的事項

由於InnoDB的索引的方式經過主鍵彙集數據,嚴重依賴主鍵。索引若是沒有定義主鍵,那麼InnoDB會選擇一個惟一的非空索引代替。若是沒有這樣的索引,InnoDB會隱式定義一個主鍵來做爲聚簇索引。

聚簇索引的優勢有:

1.能夠把相關數據存儲在一塊兒,減小數據查詢時的磁盤I/O

2.數據訪問更快,由於聚簇索引就是表,索引和數據保存在一個B+Tree中

3.使用索引覆蓋的查詢時能夠直接使用頁節點中的主鍵值

聚簇索引的缺點有:

1.插入速度嚴重依賴插入順序

2.更新聚簇索引列的代價很高,由於會強制InnoDB把更新的列移動到新的位置

3.基於聚簇索引的表在插入新行,或者主鍵被更新致使須要移動行的時候,可能會致使「頁分裂」。當行的主鍵值要求必須將這一行插入到已滿的頁中時,存儲引擎會將該頁分裂爲兩個頁面來容納該行,這就是一次頁分裂操做,頁分裂會致使表佔用更多的存儲空間。

畫外音:關於,咱們在上一篇文章中也提到過。頁是計算機管理存儲器的邏輯塊,硬件及操做系統每每將主存和磁盤存儲區分割爲連續的大小相等的塊,每一個存儲塊稱爲一頁。存和磁盤以頁爲單位交換數據。數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每一個節點只須要一次磁盤I/O就能夠徹底載入

基於聚簇索引以上的這些特色,在InnoDB中,咱們應該儘可能使用和應用無關的主鍵,例如自增主鍵,這樣能夠保證數據行是按照順序寫入的。而不是使用GUID、UUID生成隨機的主鍵。

向聚簇索引中插入順序的索引值:

每條新紀錄老是在前一條記錄的後面插入:

mark

當頁被插滿後,繼續插入到新的頁:

mark

向聚簇索引中插入隨機的索引值:

新的記錄可能被插入到以前記錄的中間,致使須要強制移動以前的記錄:

mark

被寫滿且已經刷到磁盤上的頁可能會被從新讀取用於再次插入,此時還須要進行頁分裂:

mark

總結

MyISAM和InnoDB兩個存儲引擎的索引雖然都是使用的B+Tree數據結構,可是在具體實現上仍是存在不小差異的。InnoDB支持聚簇索引,聚簇索引就是表,因此InnoDB不用像MyISAM那樣須要獨立的行存儲。也就是說,InnoDB的數據文件自己就是索引文件。而MyISAM的數據文件和索引文件是分開存儲的。能夠經過MyISAM和InnoDB如何存放表的抽象圖幫助快速理解。

InnoDB(聚簇)表分佈:

mark

MyISAM(非聚簇)表分佈:

mark

參考

推薦閱讀

MySQL——經過EXPLAIN分析SQL的執行計劃

MySQL——索引基礎

MySQL——索引優化實戰

數據庫索引背後的數據結構

是什麼影響了數據庫索引選型?

mark
相關文章
相關標籤/搜索