B 樹 B+樹 mysql索引,性能分析

接着上一篇對紅黑樹的分析,本文對B樹,及其應用進行介紹。html

http://blog.csdn.net/v_july_v/article/details/6530142  算法自己的分析mysql

http://tech.meituan.com/mysql-index.html  mysql性能 慢查詢 分析算法

http://blog.codinglabs.org/articles/theory-of-mysql-index.html   mysql索引算法分析sql

http://yemengying.com/2016/05/24/mysql-tuning/數據庫

https://segmentfault.com/a/1190000003072424  mysql索引segmentfault

 

在通常狀況下,紅黑樹的查找性能確實已經足夠好了,可是在數據足夠的大的狀況下,好比說數據庫中的數據,單純的以紅黑樹的算法查找仍是要花必定的時間,好比說數據庫通常存儲廳磁盤上,而數據量大,樹的深度一定高,磁盤IO讀寫過多(會致使磁盤頻繁的移動,而移動就是最消耗時間的)。解決方案就是磁盤的一次查找可以縮小數據的範圍,而不只僅是2叉樹的查找僅過濾掉一半的數據。若是 有一種算法 可使得每次查找後,可以過濾掉部分的數據,而不只僅是一半的數據,這樣效率很提升不少。所以相似2叉樹的多叉樹應運而生。緩存

硬件數據結構

關於磁盤的硬件原理,網上有不少資料,在此不在詳細介紹,本文只作介紹。記住一點,磁盤上的數據的讀寫  時間 由 數據的定位(查找柱面號、盤面號、塊號 經過移動臂肯定柱面,盤片的旋轉肯定 磁道上的盤號),的 查找時間,和以及  運算傳輸到內存的時間。前者比後者大的不是一個數據級的,所以,儘可能減少數據的查找是提升查找速度的有效辦法。性能

B樹mysql索引

B樹 在國內也被人稱爲B-樹。

B 樹是爲了磁盤或其它存儲設備而設計的一種多叉(相對於二叉,B樹每一個內結點有多個分支,即多叉)平衡查找樹。不少數據庫系統用的就是 B樹或者其變形的結構。

以下一顆高度爲3,度樹爲3,階樹爲4的樹。 

B樹的性質 :

用度或者 階定義數,大同小異。本質是同樣的。以階來定義,階數爲m, 每一個結點的最小子樹爲[m/2] 的上界,向下取整數。最大爲m-1。也就是說 內結點的最大子樹爲m。節點元素個數  [ceil(m / 2)-1]<= n <= m-1

而樹的高度  

關於B-Tree有一系列有趣的性質,例如一個度爲d的B-Tree,設其索引N個key,則其樹高h的上限爲logd((N+1)/2),檢索一個key,其查找節點個數的漸進複雜度爲O(logdN)。從這點能夠看出,B-Tree是一個很是有效率的索引數據結構。

B+樹

如上圖所示,是一個B樹,節點中還要包含元素的值,而在總結點必定的狀況下,每一個結點所佔的空間是相對穩定的,由爲涉及到盤塊大多的話,一個節點須要涉及到好幾回IO,效率 不高,所以,在節點空間必定狀況下,儘可能存儲多的元素個數。

B+ 樹 

B+-tree的內部結點並無指向關鍵字具體信息的指針。所以其內部結點相對B 樹更小。若是把全部同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的須要查找的關鍵字也就越多。相對來講IO讀寫次數也就下降了。

    舉個例子,假設磁盤中的一個盤塊容納16bytes,而一個關鍵字2bytes,一個關鍵字具體信息指針2bytes。一棵9階B-tree(一個結點最多8個關鍵字)的內部結點須要2個盤快。而B+ 樹內部結點只須要1個盤快。當須要把內部結點讀入內存中的時候,B 樹就比B+ 樹多一次盤塊查找時間(在磁盤中就是盤片旋轉的時間)。

索引 

MySQL官方對索引的定義爲:索引(Index)是幫助MySQL高效獲取數據的數據結構。而mysql不一樣的引擎使用不一樣的索引結構。 而本文研究的是B+樹實現的索引。

使用B+樹的緣由

通常來講,索引自己也很大,不可能所有存儲在內存中,所以索引每每以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程當中就要產生磁盤I/O消耗,相對於內存存取,I/O存取的消耗要高几個數量級,因此評價一個數據結構做爲索引的優劣最重要的指標就是在查找過程當中磁盤I/O操做次數的漸進複雜度。換句話說,索引的結構組織要儘可能減小查找過程當中磁盤I/O的存取次數。

而內存數據的讀寫不存在機械操做,僅與次數據相關,與數據的距離無關。

MySQL索引實現  

這部分引用自    http://blog.codinglabs.org/articles/theory-of-mysql-index.html  中關於mysql索引的介紹

myISAM索引實現

MyISAM引擎使用B+Tree做爲索引結構,葉節點的data域存放的是數據記錄的地址。下圖是MyISAM索引的原理圖:

 

 

在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是惟一的,而輔助索引的key能夠重複。

MyISAM的索引方式也叫作「非彙集」的,之因此這麼稱呼是爲了與InnoDB的彙集索引區分。

InnoDB索引實現

雖然InnoDB也使用B+Tree做爲索引結構,但具體實現方式卻與MyISAM大相徑庭。

第一個重大區別是InnoDB的數據文件自己就是索引文件。從上文知道,MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件自己就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以InnoDB表數據文件自己就是主索引。

 

第二個與MyISAM索引的不一樣是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的全部輔助索引都引用主鍵做爲data域。使用輔助索引須要查找 兩次索引。彙集索引這種實現方式使得按主鍵的搜索十分高效,可是輔助索引搜索須要檢索兩遍索引:首先檢索輔助索引得到主鍵,而後用主鍵到主索引中檢索得到記錄。

MySQL中的索引能夠以必定順序引用多個列,這種索引叫作聯合索引,通常的,一個聯合索引是一個有序元組<a1, a2, …, an>,其中各個元素均爲數據表的一列。

 

最左前綴原理

只能按指定的順序,依次匹配,若是中間某一條件,沒法精確匹配,則後面條件無用。

索引選擇性與前綴索引

ELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles;

前綴索引 能夠 減少 聯合索引的長度。前綴索引兼顧索引大小和查詢速度,可是其缺點是不能用於ORDER BY和GROUP BY操做,也不能用於Covering index(即當索引自己包含查詢所需所有數據時,再也不訪問數據文件自己)。

InnoDB的主鍵選擇與插入優化

在使用InnoDB存儲引擎時,若是沒有特別的須要,請永遠使用一個與業務無關的自增字段做爲主鍵。

常常看到有帖子或博客討論主鍵選擇問題,有人建議使用業務無關的自增主鍵,有人以爲沒有必要,徹底可使用如學號或身份證號這種惟一字段做爲主鍵。不論支持哪一種論點,大多數論據都是業務層面的。若是從數據庫索引優化角度看,使用InnoDB引擎而不使用自增主鍵絕對是一個糟糕的主意。

上文討論過InnoDB的索引實現,InnoDB使用匯集索引,數據記錄自己被存於主索引(一顆B+Tree)的葉子節點上。這就要求同一個葉子節點內(大小爲一個內存頁或磁盤頁)的各條數據記錄按主鍵順序存放,所以每當有一條新的記錄插入時,MySQL會根據其主鍵將其插入適當的節點和位置,若是頁面達到裝載因子(InnoDB默認爲15/16),則開闢一個新的頁(節點)。

若是表使用自增主鍵,那麼每次插入新的記錄,記錄就會順序添加到當前索引節點的後續位置,當一頁寫滿,就會自動開闢一個新的頁。以下圖所示:

 

這樣就會造成一個緊湊的索引結構,近似順序填滿。因爲每次插入時也不須要移動已有數據,所以效率很高,也不會增長不少開銷在維護索引上。

若是使用非自增主鍵(若是身份證號或學號等),因爲每次插入主鍵的值近似於隨機,所以每次新紀錄都要被插到現有索引頁得中間某個位置:

 

此時MySQL不得不爲了將新記錄插到合適位置而移動數據,甚至目標頁面可能已經被回寫到磁盤上而從緩存中清掉,此時又要從磁盤上讀回來,這增長了不少開銷,同時頻繁的移動、分頁操做形成了大量的碎片,獲得了不夠緊湊的索引結構,後續不得不經過OPTIMIZE TABLE來重建表並優化填充頁面。

所以,只要能夠,請儘可能在InnoDB上採用自增字段作主鍵。

相關文章
相關標籤/搜索