MySQL innoDB索引底層原理詳解以及與MyISAM區別

摘要本文介紹MySQL的InnoDB索引相對底層原理相關知識,涉及到B+Tree索引和Hash索引,但本文主要介紹B+Tree索引,其中包括聚簇索引和非聚簇索引,InnoDB數據頁結構詳解,B+Tree索引的使用以及優化,同時還有B+Tree索引的查詢流程簡介。此文是我對學習InnoDB索引的一個總結,內容主要參考MySQL技術內幕 InnoDB存儲引擎一書,及網上一些博客(參考文獻會給出)一、先從B+Tree入手 B+樹的特性 因作者文筆有限,B+樹的定義如果在這裏重複列出的話,應該只會讓大家更困惑,同時相信任何一本數據結構書中都能找到其複雜的定義。但是爲了便於讀者理解接下來的內容,下面只是簡單的介紹一下B+樹的幾個本文中會用到的特性。 B+樹是爲磁盤或其他直接存取輔助設備而設計的一種平衡查找樹(如果不知道平衡查找樹,請自行google),在B+樹中,所有記錄節點都是按鍵值的大小順序存放在同一層的葉節點中,各葉節點指針進行連接。 下圖是在網上找的一張B+樹示意圖

二、InnoDB數據頁結構 1.頁介紹 頁是InnoDB存儲引擎管理數據庫的最小磁盤單位。頁類型爲B-Tree node的頁,存放的即是表中行的實際數據了。 InnoDB中的頁大小爲16KB,且不可以更改 InnoDB可以將一條記錄中的某些數據存儲在真正的數據頁面之外,即作爲行溢出數據。MySQL的varchar數據類型可以存放65535個字節,但實際只能存儲65532個。同時InnoDB是B+樹結構的,因此每個頁中至少應該有兩個行記錄,否則失去了B+樹的意義,變成了鏈表,所以一行記錄最大長度的閾值是8098,如果大於這個值就會將其存到溢出行中。

 

2.InnoDB數據頁組成部分 File Header(文件頭) Page Header(頁頭) Infimun + Supremum Records User Records(用戶記錄,即行記錄) Free Space(空閒空間) Page Directory(頁目錄) File Trailer(文件結尾信息) 這也是我摘抄的書上的內容,下面我只介紹一下會幫助理解底層原理的部分。

1.在File header中,FIL+PAGE_PREV,FIL_PAGE_NEXT兩個表示當前頁的上一頁和下一頁,由此可以看出葉子節點是雙向鏈表串起來的。如下圖

2.Infimum和Supremum記錄 在InnoDB存儲引擎中,每個數據頁中有兩個虛擬的行記錄,用來限定記錄的邊界。Infimum記錄是比該頁中任何主鍵值都要小的值,Supremum指比任何可能大的值還要大的值。這兩個值在頁創建時被建立,並且在任何情況下不會被刪除。

由上圖可以看出,行記錄是記錄在頁中的,同時是在頁內行記錄之間也是雙向鏈表鏈接的(在網上有看到說是單鏈表的) 3.Page Directory 頁目錄中存放了記錄的相對位置,有些時候這些記錄指針稱爲Slots(槽)或者目錄槽,與其他數據庫不同的是,InnoDB並不是每個記錄擁有一個槽,InnoDB中的槽是一個稀疏目錄,即一個槽中可能屬於多個記錄,最少屬於4個目錄,最多屬於8個目錄。槽中記錄按照鍵順序存放,這樣可以利用二叉查找迅速找到記錄的指針。但是由於InnoDB中的Slots是稀疏目錄,二叉查找的結果只是一個粗略的結果,所以InnoDB必須通過recorder header中的next_record來繼續查找相關記錄。同時slots很好的解釋了recorder header中的n_owned值的含義,即還有多少記錄需要查找,因爲這些記錄並不包括在slots中。

 

三、查詢B+樹索引的流程 首先通過B+樹索引找到葉節點,再找到對應的數據頁,然後將數據頁加載到內存中,通過二分查找Page Directory中的槽,查找出一個粗略的目錄,然後根據槽的指針指向鏈表中的行記錄,之後在鏈表中依次查找。 需要注意的地方是,B+樹索引不能找到具體的一條記錄,而是隻能找到對應的頁。把頁從磁盤裝入到內存中,再通過Page Directory進行二分查找,同時此二分查找也可能找不到具體的行記錄(有可能會找到),只是能找到一個接近的鏈表中的點,再從此點開始遍歷鏈表進行查找。

四、聚簇索引與非聚簇索引 B+樹索引可以分爲聚集索引和輔助索引,他們不同點是,聚集索引的行數據和主鍵B+樹存儲在一起,輔助索引只存儲輔助鍵和主鍵。 1.聚集索引 聚集索引是按每張表的主鍵構造的一顆B+樹,並且葉節點中存放着整張表的行記錄數據,因此也讓聚集索引的節點成爲數據頁,這個特性決定了索引組織表中數據也是索引的一部分。由於實際的數據頁只能按照一顆B+樹進行排序,所以每張表只能擁有一個聚集索引。查詢優化器非常傾向於採用聚集索引,因爲其直接存儲行數據,所以主鍵的排序查詢和範圍查找速度非常快。 理上的連續,而是邏輯上的,不過在剛開始時數據是順序插入的所以是物理上的連續,隨着數據增刪,物理上不再連續。 2.輔助索引 輔助索引頁級別不包含行的全部數據。葉節點除了包含鍵值以外,每個葉級別中的索引行中還包含了一個書籤,該書籤用來告訴InnoDB哪裏可以找到與索引相對應的行數據。其中存的就是聚集索引的鍵。 輔助索引的存在並不影響數據在聚集索引的結構組織。InnoDB會遍歷輔助索引並通過葉級別的指針獲得指向主鍵索引的主鍵,然後通過主鍵索引找到一個完整的行記錄。當然如果只是需要輔助索引的值和主鍵索引的值,那麼只需要查找輔助索引就可以查詢出索要的數據,就不用再去查主鍵索引了。

五、索引的管理 索引在創建或者刪除時,MySQL會先創建一個新的臨時表,然後把數據導入臨時表,刪除原表,再把臨時表更名爲原表名稱。 但是在InnoDB Plugin版本開始,支持快速創建索引。其原理是先在InnoDB上加一個s鎖,在創建過程中不需要建表,所以速度會很快。創建過程中由於加了s鎖,所以只能進行讀操作,不能寫操作。 show index form table;是查看錶中索引的信息的。 Table:索引所在的表名 Non_unique:非唯一的索引,可以看到primary key 是0,因爲必須是唯一的 Key_name:索引名稱 Seq_in_index:索引中該列的位置 Column_name:索引的列 Collation:列以什麼方式存儲在索引中。可以是A或者NULL,B+樹索引總是A,即排序的。 Cardinality:表示索引中唯一值的數目的估計值。如果非常小,那麼需要考慮是否還需要建立這個索引了。優化器也會根據這個值來判斷是否使用這個索引。 Sub_part:是否是列的部分被索引。100表示只索引列的前100個字符。 Packed:關鍵字如果被壓縮。 Null:是否索引的列含有NULL值。 Index_type:索引的類型。InnoDB只支持B+樹索引,所以顯示BTREE

六、Hash索引 InnoDB中自適應哈希索引使用的是散列表的數據結構,並且DBA無法干預。 其實這一部分的原理,非常簡單,在此就不做過多介紹了

七、InnoDB和MyISAM的區別

1.InnoDB支持事物,外鍵等高級的數據庫功能,MyISAM不支持。需要注意的是,InnDB行級鎖也不是絕對的,例如mysql執行一個未定範圍的sql時,也還是會鎖表,例如sql中like的使用

2.效率,明顯MyISAM在插入數據的表現是InnoDB所遠遠不及的,在刪改查,隨着InnoDB的優化,差距漸漸變小

3.行數查詢,InnoDB不保存行數,也就是select的時候,要掃描全表,MyISAM只需讀取保存的行數即可,這也是MyISAM查詢速度快的一個因素。

4.索引,InnoDB會自動創建Auto_Increment類型字段的索引,一般習慣應用於主鍵,即主鍵索引(只包含該字段),而MyISAM可以和其他字段創建聯合索引。

除此之外,MyISAM還支持全文索引(FULLTEXT_INDEX),壓縮索引,InnoDB不支持。

備註:MyISAM的索引和數據是分開的,並且索引是有壓縮的,內存使用率就對應提高了不少。能加載更多索引,而Innodb是索引和數據是緊密捆綁的,沒有使用壓縮從而會造成Innodb比MyISAM體積龐大不小。

InnoDB存儲引擎被完全與MySQL服務器整合,InnoDB存儲引擎爲在主內存中緩存數據和索引而維持它自己的緩衝池。InnoDB存儲它的表&索引在一個表空間中,表空間可以包含數個文件(或原始磁盤分區)。這與MyISAM表不同,比如在MyISAM表中每個表被存在分離的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制爲2GB的操作系統上。

5.服務器數據備份。InnoDB必須導出SQL來備份,LOAD TABLE FROM MASTER操作對InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,導入數據後再改成InnoDB表,但是對於使用的額外的InnoDB特性(例如外鍵)的表不適用。

備註:而且MyISAM應對錯誤編碼導致的數據恢復速度快。MyISAM的數據是以文件的形式存儲,所以在跨平臺的數據轉移中會很方便。在備份和恢復時可單獨針對某個表進行操作。

InnoDB是拷貝數據文件、備份 binlog,或者用 mysqldump,支持災難恢復(僅需幾分鐘),MyISAM不支持,遇到數據崩潰,基本上很難恢復,所以要經常進行數據備份。

6.鎖的支持。**MyISAM只支持表鎖。InnoDB支持表鎖、行鎖 行鎖大幅度提高了多用戶併發操作的新能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的

使用場景建議:

1)可靠性高或者要求事務處理,則使用InnoDB。這個是必須的。

2)表更新和查詢都相當的頻繁,並且表鎖定的機會比較大的情況指定InnoDB數據引擎的創建。

對比之下,MyISAM的使用場景:

1)做很多count的計算的。如一些日誌,調查的業務表。

2)插入修改不頻繁,查詢非常頻繁的。

MySQL能夠允許你在表這一層應用數據庫引擎,所以你可以只對需要事務處理的表格來進行性能優化,而把不需要事務處理的表格交給更加輕便的MyISAM引擎。對於 MySQL而言,靈活性纔是關鍵。

引擎原理分析

MyISAM索引結構: MyISAM索引用的B+ tree來儲存數據,MyISAM索引的指針指向的是鍵值的地址,地址存儲的是數據。B+Tree的數據域存儲的內容爲實際數據的地址,也就是說它的索引和實際的數據是分開的,只不過是用索引指向了實際的數據,這種索引就是所謂的非聚集索引

主索引如下:

輔助索引如下:

因此,過程爲: MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然後以data域的值爲地址,根據data域的值去讀取相應數據記錄。

InnoDB引擎的索引結構:

也是B+Treee索引結構。Innodb的索引文件本身就是數據文件,即B+Tree的數據域存儲的就是實際的數據,這種索引就是聚集索引。這個索引的key就是數據表的主鍵,因此InnoDB表數據文件本身就是主索引。【Java高架構師、分佈式架構、高可擴展、高性能、高併發、性能優化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分佈式項目實戰學習架構師視頻免費獲取架構羣;855355016】

InnoDB的輔助索引數據域存儲的也是相應記錄主鍵的值而不是地址,所以當以輔助索引查找時,會先根據輔助索引找到主鍵,再根據主鍵索引找到實際的數據。所以Innodb不建議使用過長的主鍵,否則會使輔助索引變得過大。

建議使用自增的字段作爲主鍵,這樣B+Tree的每一個結點都會被順序的填滿,而不會頻繁的分裂調整,會有效的提升插入數據的效率。

主索引如下:

輔助索引如下:

上圖,可以看到葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因爲InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵,如果不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整形。

而且,與MyISAM索引的不同是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作爲data域。

因此,過程爲:將主鍵組織到一棵B+樹中,而行數據就儲存在葉子節點上,若使用”where id = 13”這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對應的葉節點,之後獲得行數據。若對Name列進行條件搜索,則需要兩個步驟:第一步在輔助索引B+樹中檢索Name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引B+樹種再執行一次B+樹檢索操作,最終到達葉子節點即可獲取整行數據。

兩種索引數據查找過程如下:

 

 

 

 

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