MySQL知識梳理圖,一圖看完整篇文章: html
上一篇文章簡單的介紹了MySQL的執行流程,這一篇想詳細介紹一下索引,一直想全面搞懂索引,嘗試寫一篇關於它的博文。mysql
索引是什麼了,查閱了官方文檔。官方文檔寫了索引的做用和沒有索引會帶來全表掃描,很是費時間。 Indexes are used to find rows with specific column values quickly. Without an index, MySQL must begin with the first row and then read through the entire table to find the relevant rows.
簡單的說索引是提升查詢速度。這個很好理解,就像是之前的英文詞典,找單詞若是沒有前面目錄的話,效率很低,得全文找一遍。算法
要搞清楚索引的實現原理,先看看索引的底層實現,MySQL索引大部分採用B-Tree實現,B-Tree又有B-樹和B+樹。還有一些使用Hash索引。本文主要介紹B-Tree(Balance Tree)。sql
再說B-Tree以前,先簡單瞭解一下二叉搜索樹(Binary Search Trees)。 數據庫
一般意義上說B-Tree,通常是指B-樹,也能夠叫平衡多路搜索樹,平衡的意思能夠區瞭解一下平衡二叉樹(它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,而且左右兩個子樹都是一棵平衡二叉樹。),多路的意思就是非葉子節點的孩子至少有2個。 B-Tree的特徵也是很是燒腦,查看了算法導論書籍,也是琢磨了好久。下圖爲算法導論書中一張圖,淺陰影部分爲查找字母R時檢查過的結點。 數據結構
是否是仍是一頭霧水,接下來根據上圖一一解釋一下這幾個特徵。post
第1點是說每個節點包括的信息:n表示結點中存儲關鍵字的個數,好比上圖上M的左孩子就存了2個關鍵字,D和H;x.key,說的是具體的關鍵字的信息,好比D,D實際是有2個部分組成,能夠理解爲一個map,{key: data},x.key廣義上就是表示這個map,包括了具體的key和存儲的數據data,一般說是一條記錄;x.leaf是說整個結點是不是葉子結點。性能
第2點表示若是不是葉子結點,每一個結點還有一個屬性,就是指向它n個孩子的指針,好比上圖中的DH結點,有3個孩子,則有3個指針指向本身的孩子。優化
第3點表示說每一個結點的關鍵字按小到大的順序依次排列,同時各個結點之間也知足上面提到的二叉搜索樹的特色,左孩子的值<父親節點的值<右孩子的值。ui
第4點是說每一個葉子結點高度同樣,看圖就能夠明白,這也是平衡二字的由來。
第5點說的每一個結點關鍵字的數量的限制,不可能每一個結點能夠無限存儲關鍵字。t是最小度數,須要理解這些,能夠谷歌一下度數和階數的定義,上圖是4階的B-Tree。上圖中t=2,則每一個內部結點能夠容許有二、三、4個孩子。孩子數範圍[t, 2t],每一個結點的關鍵字範圍[t-1, 2t-1]。這個要區分。
下面更加形象的給出4階的B-Tree。
因爲B-Tree的特性,在B-Tree中按key檢索數據的算法很是高效:首先從根節點進行二分查找,若是找到則返回對應節點的data,不然對相應區間的指針指向的節點遞歸進行查找,直到找到節點或找到null指針,前者查找成功,後者查找失敗。
終於寫完了B-樹,B+樹實際上是B-樹變種。 與B-樹最大的區別是內部結點不存儲data,只存儲key。以下圖:
通常數據庫系統中使用的B+樹再上圖經典的基礎上再進行了優化,變成了帶順序訪問指針的B+樹, 以下圖。這樣就提升區間訪問的性能,例如若是要查詢key爲從18到49的全部數據記錄,當找到18後,只需順着節點和指針順序遍歷就能夠一次性訪問到全部數據節點,極大提到了區間查詢效率。
數據導論書中開頭就是說: B樹是爲磁盤或其餘直接存取的輔助存儲設備而設計的一種平衡搜索樹。上面提到了輔助存儲設備,那咱們就來看看其中原理,到底由來是什麼? 計算機系統有主存和基於磁盤的輔存,主存一般就是咱們說的RAM,也就是內存,這裏不展開說它。索引文件自己很大,通常不會存在內存裏,所以索引每每是以文件的形式存儲在磁盤裏,因此索引檢索須要磁盤I/O操做。下圖爲一個典型的磁盤驅動器。
爲了縮短磁盤讀取的時間,計算機作了一些優化:磁盤預讀。磁盤預讀是基於局部性原理:當一個數據被用到時,其附近的數據也一般會立刻被使用。因此磁盤I/O操做時不光把當前磁盤地址的數據,而是把相鄰的數據也都讀取到內存緩衝區內,由於局部性原理告訴咱們,當計算機訪問一個地址的數據的時候,與其相鄰的數據也會很快被訪問到。
預讀的長度通常爲頁(page)的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操做系統每每將主存和磁盤存儲區分割爲連續的大小相等的塊,每一個存儲塊稱爲一頁(在許多操做系統中,頁得大小一般爲4k),主存和磁盤以頁爲單位交換數據。
說了那麼多,總結一下:
數據庫系統巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每一個節點只須要一次I/O就能夠徹底載入。B-樹也利用這一點,每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,加之計算機存儲分配都是按頁對齊的,就實現了一次磁盤I/O就讀取了一頁的數據。下面是B-樹的示例圖:
下面附一張B+樹的直觀圖:
通常3層B+樹能夠存儲上百萬的數據,也就是讀取上百萬的數據,只須要3次磁盤I/O,可見這效率,大大提高了。若是沒有索引,那每次查詢一次數據項,都須要一次I/O,幾百萬次,可怕。
MyISAM的索引採用B+樹實現,MyISAM的索引和數據時分開的,葉子節點data存取的是數據的地址。以下主鍵索引的示例圖:
由圖能夠看出,要根據索引找到數據,先根據索引找到葉子節點,再根據葉子節點找到數據的地址,而後再根據數據地址取出數據。
MyIASM的輔助索引的實現與主鍵索引沒有區別,以下圖:
單獨出來講,是爲了待會跟InnoDB做區分。
InnoDB,在實際項目接觸是很是多的,索引的實現也是使用B+樹,可是實現原理跟MyISAM不一樣。 第一個區別是InnoDB的數據文件自己就是索引文件。MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件自己就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以InnoDB表數據文件自己就是主索引。以下圖:
這種索引叫作彙集索引。由於InnoDB的數據文件自己要按主鍵彙集,因此InnoDB要求表必須有主鍵(MyISAM能夠沒有),若是沒有顯式指定,則MySQL系統會自動選擇一個能夠惟一標識數據記錄的列做爲主鍵,若是不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段做爲主鍵,這個字段長度爲6個字節,類型爲長整形。
第二個區別就是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的全部輔助索引都引用主鍵做爲data域。以下圖所示:
瞭解不一樣的引擎的實現原理,對於咱們平常作數據庫的設計是很是有幫助的。
這一篇先到這裏吧,下一篇總結索引的優化策略。
參考:
1. http://blog.codinglabs.org/articles/theory-of-mysql-index.html
2. 算法導論(第三版)
複製代碼
更多精彩文章,請關注公衆號:「 天澄技術雜談 」