Mysql優化(1):索引原理-B+樹

什麼是索引

    首先,我們經常會聽到一個說法:怎麼對mysql進行優化。十個裏有九個半會說:加索引,索引優化啊。確實,對mysql進行優化,最有效、最能解決問題、最普遍的方式就是設計合適的索引,正確的索引能夠將查詢效率提升好幾個數量級。爲什麼索引能夠顯著提升查詢效率呢,我們從索引結構來一點點討論。
    索引是什麼,從mysql官方文檔來說:索引是幫助Mysql高效獲取數據的排好序的數據結構!
這裏有兩個重點:排好序數據結構,什麼是數據結構:就像鏈表,數組,樹形,圖這樣用來組織存儲數據的方式。而Mysql索引用的是一種叫做B+樹的數據結構來存儲數據的,而且這樣存儲的數據是有序的。那又延伸出是B+樹的概念了,爲了理解這個,我們先弄清楚二叉樹的概念

二叉樹

在這裏插入圖片描述
有一張有兩列col1、col的表 t 如上圖。爲col2列建立索引,右邊就是一個二叉樹,它的特點是:

  1. 非葉子節點最多有兩個子節點
  2. 節點右邊的數據>=節點數據
  3. 節點左邊的數據<節點數據

假設我現在要查找 col2=77 的數據,從根節點開始找,要查找3次,路徑爲34 --> 89 --> 77。如果數據總量爲N,那麼最多需要查找的次數爲log2N。但是mysql最終沒有采用二叉樹來做爲索引的結構,爲什麼呢?我們來考慮以下情形:如果爲col1列建立索引呢,它是一個自增序列。那麼構建出來的二叉樹就是這樣的。

在這裏插入圖片描述
它變成了一個單向鏈表,查詢數據得進行全表掃描。如果有100萬行數據,它最多就可能會找100萬次,這個效率是不可接受的。
所以二叉樹作爲索引結構是不合適的。那又提出了第二種方案:紅黑樹(也叫平衡二叉樹)

紅黑樹

紅黑樹,Red-Black Tree 「RBT」是一個自平衡(不是絕對的平衡)的二叉查找樹(BST),它是自平衡的,它不會出現上面那樣一條線的鏈表結構。
在這裏插入圖片描述
有新數據插入時,它會根據自身的情況進行自平衡,讓自己始終保持一個二叉樹的形狀。它最終也沒有被Mysql採用,主要是因爲:

  1. 如果數據量過大,幾百萬甚至千萬級別,那麼樹的深度可能達到20以上, 在這裏插入圖片描述
    數據量達到200萬的時候,已經需要搜索20次以上了。也就意味着20次的磁盤I/O,這個開銷太大了。
  2. 自平衡的代價過大,例如一個20層的紅黑樹結構,新增了一個在第二層的數據,那麼後面的18層結構都要變動,代價太大。
    那有沒有更好的辦法呢!這就開始談到B樹了(不是B+樹)

B樹(B Tree)

上面的紅黑樹不合適的主要原因就在於當數據量達到百萬級時(這是實際數據的常見情況,數據量不過萬的情況下沒必要建索引)樹的深度過高。那我們就想辦法降低樹的高度?怎麼做呢。。。。。。。
好傷腦筋啊,怎麼辦?log2N的複雜度已經很可以了,還怎麼減少樹高度呢!
對了!我們可以增加樹的寬度,也就是將樹進行橫向拓展,沒必要說每層只有一個節點啊,多放幾個節點不就ok了嗎!就像這樣
在這裏插入圖片描述
這就是B樹,它的主要特點是:

  1. 葉子節點具有相同的深度,葉子節點的指針爲空
  2. 所有索引元素不重複
  3. 節點中的數據從左到右遞增排列。

每個節點由兩部分組成:指針項和數據存儲項(data部分)
指針指向下一個節點,數據項存儲索引所在行除了索引列之外的數據。
如果一層有1000個節點,那麼三層結構能夠存儲的數據量可以達到1000*1000*1000=10億,這個數據量完全能滿足我們的需要!然而這個結構有兩個缺陷:

  1. 每層的最大大小(頁大小)在MySql中是固定的:16Kb。如果一個表的列數很多:那麼每一行的數據量(除索引列之外的所有列的數據)就比較大,可能達到1Kb。那麼每層能存儲的節點數可能就不到16個。這樣就大大降低了查詢效率!
  2. 實際查詢中,我們除了等於條件查詢外,更多的是範圍查詢 a<x<b 這種的,B樹結構就有點不滿足要求了!

B+ 樹(B+ Tree)

    由此產生了 B+ 樹,它是 B樹的變種。

在這裏插入圖片描述
它有以下特點:

  1. 非葉子節點不存儲data數據,只存儲索引,可以橫向放置更多的數據。
  2. 葉子節點包含所有索引字段
  3. 葉子節點用指針連接,提高區間訪問的性能,並且最後一個葉子節點和第一個節點之間也有一個指針,形成一個閉環。

現在我們來算算三層的 B+數能放多少數據。以索引字段爲bigInt類型爲例:bigInt類型佔 8Bytes,索引結構佔 6Bytes。
每層最大大小爲 16Kb(通過InnodbPageSize參數配置,不建議自行修改該數據,可能造成不可測的後果)。第一層可以放
16Kbytes/14Bytes=1170個數據項。
第三層是放具體數據的,data的大小不固定,我們取大的值吧。假設一個表有100個字段(這個數量已經儘量誇大了),平均字段長度爲8Bytes ( int爲4Bytes, bigInt爲8Bytes,float爲4Bytes, double爲8Bytes) ,一行的數據量爲800Bytes,我們以 1Kbytes計算好了,那麼第三層每個節點可以存放16Kb/1Kb=16個數據。

    三層結構可以存儲 1170*1170*16=21902400個數據。2000多萬!我們已經儘量低估三層結構所能存儲的數據量了。也就是說2000萬的數據量,加了索引之後只要三次查找就可以查找到數據。
我們也注意到,因爲數據只存儲在葉子節點上,哪怕這個數據就在第一個的位置上,我們還是要經過三次查找才能找到數據。索引數據量如果很少,建索引反而會降低效率!

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