mysql索引及索引的存儲結構


前言:首先推薦一個數據結構可視化的網站:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html,本文不做過深的數據結構剖析,但是要簡單瞭解一些數據結構的特性和概念。
瞭解索引的存儲結構前,我們必須要先了解一些索引的基本概念。

什麼是索引

索引:就是數據庫管理系統中一個排序的數據結構,協助快速查詢和更新表中數據。注意索引是放在磁盤上的
建立索引的方式:
1.建表的時候就創建
2.建完表後續想添加索引:alter table 表名 add index 索引名(字段名);
索引的類型:
1.normal:普通索引,非唯一的索引沒有任何限制
2.unique:唯一索引,要求字段的值不能重複。(primary key主鍵索引,特殊的唯一索引,主鍵索引所在的列字段必須NOT NULL)
3.full Text:全文索引,如果要在一個大文本里匹配一個字符那麼就可以創建一個全文索引。char、varchar、text這些類型才能創建全文索引,匹配語法:select * from 表名 where match(字段名) against(‘要匹配的字符’ in natural language mode);

索引的存儲結構

我們都知道mysql中的索引有BTREE和HASH,而最常使用的就是BTREE。那麼問題來了,爲什麼mysql當初的設計者要選擇使用B樹呢?

如果使用有序數組

我們知道數組有下標,像’=’,’>’,’<'這些查詢效率會很高,但是,更新索引時就會出現挪動大量數據,改變數據下標,所以這並不適合作爲mysql的存儲結構。

如果使用單鏈表

針對上邊問題,我們會先想到使用鏈表來解決更新問題,因爲鏈表記錄的有上個節點和下個節點的地址。但是看,插入和更新快了,他的查詢效率大大減少,因爲單鏈表不支持二分查詢,所以說查詢效率是很低的。那麼有沒有使用二分查找的鏈表呢?

如果使用二分查找樹(Binary Search Tree)

二分查找樹簡稱BST
特點:左子樹的值都要小於父節點,右子樹的值都要大於父節點。
缺點:如圖所示,如果是有序的插入,那麼BST樹就會變成一個線性的鏈表(斜樹,不平衡樹),深度會很大。導致查詢會很慢。所以也並不適合mysql的索引結構

在這裏插入圖片描述

平衡二叉樹(AVL樹)

AVL也就是發明者的名字簡寫。
特點:基於二叉樹,但左右子樹的深度差得絕對值不超過1。如果右子樹的深度和左子樹的深度絕對值超過1,就會發生左旋(反之右旋),如下圖:
在這裏插入圖片描述
缺點:如果mysql採用這種方式存儲索引,那麼我們看下圖存儲示例:
在這裏插入圖片描述
假設我們要找37這條數據,我們去索引樹上找,第一次拿到磁盤塊1之後,要到server層來比較發現我們要找的數據比他大,就到右子樹上找下個磁盤塊,繼續比較發現又小了,就繼續到左子樹找下個磁盤塊。纔拿到所需數據。

我們要知道,我們每次訪問樹節點的時候就是和磁盤的一次IO,將磁盤數據加載進內存。前邊文章說過,在InnoDB中,IO操作的最小單位是頁(page),默認是16kb。但是,如上圖,一個節點只存儲了那麼點東西,是遠遠不夠16kb的(16384個字節),所以說,使用AVL樹每次IO都會浪費大量的空間,而且放的節點越多,IO次數也就越多,浪費的空間也就越大,所需時間也越多

比如上圖中,要查找37這條數據,就要3次IO,如果有成千上萬條數據呢,IO時間是無法估量的。
思考一下如何解決這一問題呢?我們可以讓每個節點存儲更多的數據,可以讓二叉變成多叉(“叉數”也就是“路數”也稱爲“度”) ,這樣可以讓樹的深度減少,IO次數也就越少,查詢速度也就越快。

多路平衡查找樹(B Trees)

我們來看,和上圖同樣的數據,在B樹中要找37這條數據,如下圖,只需要兩次IO就可以了。數據量越大效果也就越明顯。
在這裏插入圖片描述
那麼這個B樹是如何實現一個節點存儲多個數據並且還保持平衡的呢?
分裂和合並:假如路數是3,也就是一個節點只能放兩個數據,如果要插入第三個數據即路數即將超過3,將會產生分裂(反之合併)。如下圖:
在這裏插入圖片描述
mysql中索引用的B樹,並不是該B樹,而是用的增強版的B+樹,接下來我們瞭解一下,什麼是B+樹。

加強版多路平衡樹(B+ Trees)

特點:和B樹不同的是
1.B+樹的節點上有幾個數據,就有幾路。
2.每個父節點的元素都會出現在子節點上,是子節點的最大或最小元素。
3.只有葉子節點才存儲數據,並且每個葉子節點都有指向下一個節點的指針,形成一個有序鏈表。
在這裏插入圖片描述
我們來看一看B+樹 有多強大:
假設存儲bigint類型(8bytes),InnoDB中的指針大小爲6bytes,所以這樣的一個索引就是14個字節,每個節點16kb(16384個字節),那麼一個節點就可以存放16384/14=1170路。那麼子節點就可以存放11701170=1368900個索引也就有1368900路。那麼假設一條數據1k,一個葉子節點16k可以存放16條記錄,那麼1368900路的葉子節點共可以存放136890016=21902400條記錄,也就是兩千多萬條記錄,樹的深度只有2,查找數據只需三次IO。

不僅如此,B+樹葉子節點還是一個有序的鏈表,如果我們進行範圍的查找,如where id> 18 and id < 30,這種的條件查詢,如果是B樹他每次都會在根節點開始遍歷查找,而B+樹一次查找就可以沿着葉子節點的鏈表指針檢索出所需數據。

B+樹的優勢:
1.單一節點存儲更多的元素,使得查詢的IO次數更少。
2.所有查詢都要查找到葉子節點,查詢性能穩定。
3.所有葉子節點形成有序鏈表,便於範圍查詢。

簡單瞭解HASH索引

因爲hash索引用的並不多,簡單瞭解下:
hash方式在我們的索引裏面去存儲了鍵值和映射關係,會根據索引的字段去生成hash碼和指針,指針指向數據,他的時間複雜度是永恆不變的O(1),查詢速度很快。
不足之處:
1.生成hash碼是無序的
2.只能做等值的查詢,因爲它要根據鍵計算出hash碼,所以只能是根據key去查value這種形式
3.如果字段有很多重複的值,就會產生大量的hash衝突。
所以一般不會使用hash方式作爲索引的存儲結構

<<上一篇:InnoDB存儲引擎的磁盤架構

>>下一篇:mysql索引在存儲引擎中的實現及索引的使用原則

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