Stories

Detail Return Return

分享會上狂吹MySQL的4大索引結構,沒想到大家的鑑賞能力如此的~~~~ - Stories Detail

文章內容整理自【博學谷狂野架構師】

索引(index)是幫助MySQL高效獲取數據數據結構(有序)。在數據之外,數據庫系統還維護着滿足 特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據, 這樣就可以在這些數據結構 上實現高級查找算法,這種數據結構就是索引。

file
優缺點:

優點:

  • 提高數據檢索效率,降低數據庫的IO成本
  • 通過索引列對數據進行排序,降低數據排序的成本,降低CPU的消耗

缺點:

  • 索引列也是要佔用空間的
  • 索引大大提高了查詢效率,但降低了更新的速度,比如 INSERT、UPDATE、DELETE

索引結構

索引結構 描述
B+Tree 最常見的索引類型,大部分引擎都支持B+樹索引
Hash 底層數據結構是用哈希表實現,只有精確匹配索引列的查詢才有效,不支持範圍查詢
R-Tree(空間索引) 空間索引是 MyISAM 引擎的一個特殊索引類型,主要用於地理空間數據類型,通常使用較少
Full-Text(全文索引) 是一種通過建立倒排索引,快速匹配文檔的方式,類似於 Lucene, Solr, ES
  • 上述是MySQL中所支持的所有的索引結構,接下來,我們再來看看不同的存儲引擎對於索引結構的支持 情況。
索引 InnoDB MyISAM Memory
B+Tree索引 支持 支持 支持
Hash索引 不支持 不支持 支持
R-Tree索引 不支持 支持 不支持
Full-text 5.6版本之後支持 支持 不支持
注意: 我們平常所説的索引,如果沒有特別指明,都是指B+樹結構組織的索引。

二叉樹

假如説MySQL的索引結構採用二叉樹的數據結構,比較理想的結構如下:

file

如果主鍵是順序插入的,則會形成一個單向鏈表,結構如下:
file

所以,如果選擇二叉樹作為索引結構,會存在以下缺點:

  • 順序插入時,會形成一個鏈表,查詢性能大大降低。
  • 大數據量情況下,層級較深,檢索速度慢。

此時大家可能會想到,我們可以選擇紅黑樹,紅黑樹是一顆自平衡二叉樹,那這樣即使是順序插入數據,最終形成的數據結構也是一顆平衡的二叉樹,結構如下:

file

但是,即使如此,由於紅黑樹也是一顆二叉樹,所以也會存在一個缺點:

  • 大數據量情況下,層級較深,檢索速度慢。

所以,在MySQL的索引結構中,並沒有選擇二叉樹或者紅黑樹,而選擇的是B+Tree,那麼什麼是B+Tree呢?在詳解B+Tree之前,先來介紹一個B-Tree。

B-Tree

B-Tree,B樹是一種多路衡查找樹,相對於二叉樹,B樹每個節點可以有多個分支,即多叉。以一顆最大度數(max-degree)為5(5階)的b-tree為例,那這個B樹每個節點最多存儲4個key,5個指針:

file

樹的度數指的是一個節點的子節點個數。

我們可以通過一個數據結構可視化的網站來簡單演示一下。B-Tree Visualization (usfca.edu)(opens new window)

file

插入一組數據: 100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250 。然後觀察一些數據插入過程中,節點的變化情況。

file

特點:

  • 5階的B樹,每一個節點最多存儲4個key,對應5個指針。
  • 一旦節點存儲的key數量到達5,就會裂變,中間元素向上分裂。
  • B樹中,非葉子節點和葉子節點都會存放數據

B+Tree

B+Tree是B-Tree的變種,我們以一顆最大度數(max-degree)為4(4階)的b+tree為例,來看一下其結構示意圖:

file
我們可以看到,兩部分:

  • 綠色框框起來的部分,是索引部分,僅僅起到索引數據的作用,不存儲數據。
  • 紅色框框起來的部分,是數據存儲部分,在其葉子節點中要存儲具體的數據。

我們可以通過一個數據結構可視化的網站來簡單演示一下。B+ Tree Visualization (usfca.edu)(opens new window)

file
插入一組數據: 100 65 169 368 900 556 780 35 215 1200 234 888 158 90 1000 88 120 268 250 。然後觀察一些數據插入過程中,節點的變化情況。

file

最終我們看到,B+Tree 與 B-Tree相比,主要有以下三點區別:

  • 所有的數據都會出現在葉子節點
  • 葉子節點形成一個單向鏈表
  • 非葉子節點僅僅起到索引數據作用具體的數據都是在葉子節點存放的。

上述我們所看到的結構是標準的B+Tree的數據結構,接下來,我們再來看看MySQL中優化之後的B+Tree。

MySQL索引數據結構對經典的B+Tree進行了優化。在原B+Tree的基礎上,增加一個指向相鄰葉子節點的鏈表指針,就形成了帶有順序指針的B+Tree,提高區間訪問的性能,利於排序。

file

Hash

MySQL中除了支持B+Tree索引,還支持一種索引類型---Hash索引。

  1. 結構

哈希索引就是採用一定的hash算法,將鍵值換算成新的hash值,映射到對應的槽位上,然後存儲在hash表中。

file

如果兩個(或多個)鍵值,映射到一個相同的槽位上,他們就產生了hash衝突(也稱為hash碰撞),可以通過鏈表來解決。

file

  1. 特點
  • Hash索引只能用於對等比較(=,in),不支持範圍查詢(between,>,< ,...)
  • 無法利用索引完成排序操作
  • 查詢效率高,通常(不存在hash衝突的情況)只需要一次檢索就可以了,效率通常要高於B+tree索引
  1. 存儲引擎支持

在MySQL中,支持hash索引的是Memory存儲引擎。 而InnoDB中具有自適應hash功能,hash索引是 InnoDB存儲引擎根據B+Tree索引在指定條件下自動構建的。

思考題: 為什麼InnoDB存儲引擎選擇使用B+tree索引結構?

  1. 相對於二叉樹,層級更少,搜索效率高;
  2. 對於B-tree,無論是葉子節點還是非葉子節點,都會保存數據,這樣導致一頁中存儲的鍵值減少指針跟着減少,要同樣保存大量數據只能增加樹的高度,導致性能降低
  3. 相對Hash索引,B+tree支持範圍匹配及排序操作;

索引的分類

在MySQL數據庫,將索引的具體類型主要分為以下幾類:主鍵索引、唯一索引、常規索引、全文索引。

分類 含義 特點 關鍵字
主鍵索引 針對於表中主鍵創建的索引 默認自動創建,只能有一個 PRIMARY
唯一索引 避免同一個表中某數據列中的值重複 可以有多個 UNIQUE
常規索引 快速定位特定數據 可以有多個
全文索引 全文索引查找的是文本中的關鍵詞,而不是比較索引中的值 可以有多個 FULLTEXT

在 InnoDB 存儲引擎中,根據索引的存儲形式,又可以分為以下兩種:

分類 含義 特點
聚集索引(Clustered Index) 將數據存儲與索引放一塊,索引結構的葉子節點保存了行數據 必須有,而且只有一個
二級索引(Secondary Index) 將數據與索引分開存儲,索引結構的葉子節點關聯的是對應的主鍵 可以存在多個

聚集索引選取規則:

  • 如果存在主鍵,主鍵索引就是聚集索引
  • 如果不存在主鍵,將使用第一個唯一(UNIQUE)索引作為聚集索引。
  • 如果表沒有主鍵,或沒有合適的唯一索引,則InnoDB會自動生成一個rowid作為隱藏的聚集索 引。

聚集索引和二級索引的具體結構如下:

演示圖:

file

  • 聚集索引的葉子節點下掛的是這一行的數據 。
  • 二級索引的葉子節點下掛的是該字段值對應的主鍵值。

接下來,我們來分析一下,當我們執行如下的SQL語句時,具體的查找過程是什麼樣子的。

file

具體過程如下:

  1. 由於是根據name字段進行查詢,所以先根據name='Arm'到name字段的二級索引中進行匹配查 找。但是在二級索引中只能查找到 Arm 對應的主鍵值 10。
  2. 由於查詢返回的數據是*,所以此時,還需要根據主鍵值10,到聚集索引中查找10對應的記錄,最 終找到10對應的行row。
  3. 最終拿到這一行的數據,直接返回即可。

回表查詢: 這種先到二級索引中查找數據,找到主鍵值,然後再到聚集索引中根據主鍵值,獲取 數據的方式,就稱之為回表查詢。

思考題:

  • 以下兩條SQL語句,那個執行效率高? 為什麼?

    A. select * from user where id = 10 ;

    B. select * from user where name = 'Arm' ;

    備註: id為主鍵,name字段創建的有索引;

解答:

  • A 語句的執行性能要高於B 語句。
  • 因為A語句直接走聚集索引,直接返回數據。 而B語句需要先查詢name字段的二級索引,然後再查詢聚集索引,也就是需要進行回表查詢。

思考題:

  • InnoDB主鍵索引的B+tree高度為多高呢?

file

答:假設一行數據大小為1k,一頁中可以存儲16行這樣的數據。InnoDB 的指針佔用6個字節的空間,主鍵假設為bigint,佔用字節數為8. 可得公式:n * 8 + (n + 1) * 6 = 16 * 1024,其中 8 表示 bigint 佔用的字節數,n 表示當前節點存儲的key的數量,(n + 1) 表示指針數量(比key多一個)。算出n約為1170。

如果樹的高度為2,那麼他能存儲的數據量大概為:1171 * 16 = 18736; 如果樹的高度為3,那麼他能存儲的數據量大概為:1171 * 1171 * 16 = 21939856

另外,如果有成千上萬的數據,那麼就要考慮分表,涉及運維篇知識

如果本文對您有幫助,歡迎關注點贊`,您的支持是我堅持創作的動力。

轉載請註明出處!

user avatar mannayang Avatar u_17513518 Avatar debuginn Avatar xuxueli Avatar AmbitionGarden Avatar tech Avatar u_11365552 Avatar chuanghongdengdeqingwa_eoxet2 Avatar lvlaotou Avatar ahahan Avatar jkdataapi Avatar yizhidanshendetielian Avatar
Favorites 55 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.