很早以前,就從學校的圖書館借了MySQL技術內幕,InnoDB存儲引擎這本書,但一直草草閱讀,作的筆記也有些凌亂,趁着如今大四了,課程稍微少了一點,整理一下筆記,按照專題寫一些,加深一下印象,不枉讀了一遍書。與此同時,也加深一下對MySQL的瞭解,認識了原理,對優化的原則纔有把握,對問題的分析纔有源頭。html
一種是B+樹,一種是哈希。B+樹中的B表明的意思不是二叉(binary),而是平衡(balance),由於B+樹最先是從平衡二叉樹演化來的,可是B+樹又不是一個平衡二叉樹。mysql
同時,B+樹索引並不能找到一個給定鍵值的具體行。B+樹索引只能找到的是被查找數據行所在的頁。而後數據庫經過把頁讀入內存,再在內存中進行查找,最後獲得查找的數據。算法
先從二分查找法提及:sql
二分查找法的基本思想是,將記錄排序(假如從小到大排序),而後採用跳躍式的方式進行查找,以有序數列的中點位置爲比較對象,若是要找的元素小於該中點元素,那麼查找左半部分,若是要找的元素大於該中點元素,那麼久找右半部分。好比一組排好序的數:5 10 19 22 30 55 59 60 90, 若是我要查找60這個數字,那麼先找30,發現30小於60,那麼找30右半部分的中點59,發現59仍是小了,那麼找59右邊的數,從而找到了60,這樣經過不斷二分把查找須要的時間以指數級進行降低,算法效率到了Logn級別。數據庫
再說一下平衡二叉樹:數據結構
這是一幅平衡二叉樹,左子樹的值老是小於根的值,右子樹的值老是大於根的鍵值,所以能夠經過中序遍歷(以遞歸的方式按照左中右的順序來訪問子樹),所以遍歷之後獲得的輸出是九、1七、2八、3五、3九、5六、6五、87。這樣,若是要查找鍵值爲28的記錄,先找到根,而後發現根大於28,找左子樹,發現左子樹的根17小於28,再找下一層右子樹,而後找到28。經過了3次查找找到了須要找的節點。可是若是二叉樹節點分佈很是不均勻,就像第二張圖那樣,那麼若是要查找39這個節點的話,查找效率和順序查找就差很少了,最差的結果就是查找65,那麼二叉搜索樹就會徹底退化成線性表。所以若是想要最大性能地構造一個二叉查找樹,須要這顆二叉查找樹是平衡的,平衡二叉樹對於查找的性能是比較高的,可是不是最高的,只是接近最高的性能。要達到最好的性能,須要創建一顆最優二叉樹,可是最優二叉樹的創建和維護須要大量的操做,所以用平衡 二叉樹就比較好。同時,平衡二叉樹多用於內存結構對象中,所以維護他的開銷相對較小。數據結構和算法
雖然二叉查找樹和平衡二叉樹都可以實現較快的數據查找,可是,因爲數據庫的內容是存在於磁盤上,而磁盤IO與內存IO相比,比內存IO慢了10^5~10^6倍,爲了減小磁盤IO,提升檢索速度,於是才用了B+樹這種數據結構。換言之,B+樹就是爲磁盤或其餘直接存取輔助設備而設計的一種多路查找樹,是多叉樹。數據庫設計
B+樹的概念仍是過於複雜,直接上圖比較合適,來一張維基百科上的截圖:性能
從上面能夠看出,全部記錄的節點都在頁節點中,而且是順序存放的,若是咱們從最左邊的節點開始遍歷,能夠獲得的全部鍵值的順序是:一、二、三、四、五、六、7。優化
在B+樹中,全部記錄節點都是按照鍵值的大小順序存放在同一層的葉節點中,各個葉子節點經過指針進行鏈接。因爲一個節點中存放了多條的數據,那麼檢索的時候,進行的磁盤IO次數將會少掉不少。
在B+樹插入的時候,爲了保持平衡,對於新插入的鍵值可能須要作大量的拆分頁操做,而B+樹主要用於磁盤,所以頁的拆分意味着磁盤操做,所以應該在可能的狀況下儘可能減小頁的拆分。所以,B+樹提供了旋轉的功能。至於旋轉和刪除等內容,過於複雜,這篇筆記先不作記錄。只是瞭解使用B+樹的緣由以及B+樹的特性。
InnoDB存儲引擎使用匯集索引,實際的數據行和相關鍵值保存在一塊。於是,在InnoDB中要使用索引訪問數據始終須要兩次查找,而不是一次。由於索引葉子節點中存儲的不是行的物理位置,而是主鍵的值。即:二次索引-->主鍵-->數據的葉子-->經過數據葉字節點中的page directory找到數據行。
由於每一張InnoDB的表都會有一個主鍵索引,可是若是沒有顯式指定怎麼辦?若是沒有手工去指定主鍵索引的話,那麼,InnoDB引擎會指派一個unique的列做爲主鍵,若是沒有unique的字段的話,那麼便會自動生成一個隱含的列做爲主鍵。
因此,在在InnoDB的設計中,應該儘量的使用一個與業務無關auto_increment的自增主鍵,而不要去使用uuid之類的隨機(無序)的彙集鍵。同時,因爲全部的索引都使用主鍵的索引,若是主鍵索引過長,也會使輔助索引相應的變大。
彙集索引的存儲並非物理上的連續,而是邏輯上連續的。一方面,頁經過雙向鏈表鏈接,頁按照主鍵的順序排列;另外一方面,每一個頁中的記錄也是經過雙向鏈表進行維護,物理存儲上能夠一樣不按照主鍵存儲。
對於目前的MySQL來講,全部的對於索引的添加或者刪除操做,MySQL數據庫都是要先建立一張新的臨時表,而後再把數據導入臨時表,再刪除原來的表,而後再把臨時表命名爲原來的表。因此,若是一張表中數據太多的話,那麼後期添加刪除索引須要花費很長的時間,於是最好在數據庫設計初期便設計好索引。
還有,雖然InnoDB存儲引擎從版本innoDB Plugin開始,支持一種稱爲快速索引建立的方法,可是這種方法只限定於輔助索引,對於主鍵的建立和刪除仍是須要重建一張表。
[2]《MySQL技術內幕:InnoDB存儲引擎》