1. 程式人生 > >MySQL優化之索引原理(二)

MySQL優化之索引原理(二)

一,前言 

​ 上一篇內容說到了MySQL儲存引擎的相關內容,及資料型別的選擇優化。下面再來說說索引的內容,包括對B-Tree和B+Tree兩者的區別。

1.1,什麼是索引

​ 索引是儲存引擎用於快速找到記錄的一種資料結構, 對效能的提升有很大的幫助,尤其當表中數量較大的情況下,索引正確的使用可以對效能提升幾個數量級。
但是索引經常被忽略,不恰當的索引對效能可能還會帶來負面效果。

1.2,什麼時候新增索引

  • 主鍵自動建立主鍵索引(唯一索引)

  • where字句中的列,頻繁作為查詢欄位的列

  • 表連線關聯的列

  • 排序用到的列

  • 索引的基數越大(選擇性大),索引的效率就越高

    什麼叫基數越大,比如手機號,每個列都具有不同的值,非常好區別,這個就適合建立索引,而性別這樣的欄位,因為只有兩個值,以不適合建立索引,就是區分度高低的問題。

1.3,不適合新增索引

  • 表中資料太少
  • 頻繁修改的欄位
  • 資料重複且分佈平均的欄位

1.4,索引的分類

​ 單值索引:即一個索引只包含單個列,一個表可以有多個單列索引。

​ 唯一索引:索引列的值必須唯一,但是允許有空值。

​ 複合索引:即一個索引包含多個列。

​ 全文索引:使用fulltext建立全文索引。

在舊版MySQL中全文索引只能用在MyISAM表格的char、varchar和text的欄位上。新版的MySQL5.6.24上InnoDB引擎也加入了全文索引。

​ 使用方式:

  • 建立索引:create [unique|fulltext] index 索引名 on 表名 (屬性名[長度][asc|desc])。
  • 刪除索引:drop index 索引名 on 表名。
  • 檢視索引:show index from 表名。

具體使用方式這裡就不詳細說明,接下來就說說關於索引的實現原理,Tree,B-Tree,B+Tree。

二,Tree

​ 在總結B-Tree和B+Tree之前,先看看最基本的二叉樹結構吧,因為前兩種樹結構夠可以算是二叉樹的變種。

​ 二叉樹是n(n>=0)個結點的有限集合,該集合或者為空集(稱為空二叉樹),或者由一個根結點和兩棵互不相交的、分別稱為根結點的左子樹和右子樹組成。

​ 二叉樹的特點:

  • 每個結點最多有兩顆子樹,所以二叉樹中不存在度大於2的結點。
  • 左子樹和右子樹是有順序的,次序不能任意顛倒。
  • 從根節點出發,左子樹都是比根節點小的,而右子樹都是比根節點大的。

​ 因此對於較平衡的二叉樹的查詢效能,是幾乎接近於二分查詢的,但是如果存入的資料都比根節點小,或者都比根節點大,則會出現以下情況。

​ 這兩種情況分別是左斜樹和右斜樹,上述情況毫無疑問在二叉樹搜尋時,效率是非常低的。因為它已經失去了樹的結構,不管是查詢節點,還是新增刪除等,都是對每個節點依次遍歷,直到查出目標節點為止。

​ 另外還有一點也是很重要,如果二叉樹的位元組點或多,一百萬,一千萬,甚至上億資料。對於較大資料量的二叉樹,會將其儲存在磁碟中,那麼問題來了。如果要查詢的資料在樹的底層,那麼就勢必會造成多次的磁碟IO,而磁碟IO的讀取比記憶體讀取的速度要低100倍左右。這種情況下,不管是從效能來說,還是效率這都不是一個好的結果。

​ 接著再說B-Tree結構,是二叉樹的一種升級版。

三,B-Tree

​ B樹又被成為平衡多路查詢樹。

  • 樹中每個結點最多含有m個節點(且m>2)。
  • 除根結點和葉子結點外,其它每個結點至少有[m / 2,m]個孩子。
  • 若根結點不是葉子結點,則至少有2個孩子(特殊情況:整棵樹只有一個根節點)。
  • 所有葉子結點都出現在同一層。

​ 在B-Tree或者B+Tree中,都會存在一個關於度的概念,也就是上面提到的m值。什麼是度,可以說是我們自定義的一個閾值,當節點數量達到這個閾值時,樹的結構便會發生變化,此時便轉變成B-Tree結構。

​ 現在,設定度(m)為3,首先我們先插入兩個節點:

​ 發現在B樹結構中,當插入9節點時,並沒有成為8節點的右子樹,這是為什麼。首先在於這就是B樹的結構特點,沒有成為8節點的右子樹是不是就減少了樹的層級深度。其次就是我們設定B樹的度為3,接著將再新增10節點,看有什麼變化。

​ 這個時候已經達到最大值3,那麼根據二叉樹的結構特點,將9提升為根節點,8和10分別為9的左右子節點。

​ 繼續新增6

​ 新增11

​ 新增15

​ 分析:

​ 1,當新增11完成時,葉子節點全部都達到了度為2,而新增15時,由於比根節點9大,所以新增到右子樹中。則右子樹變成001000110015。顯然達到我們設定的閾值,根據以上規則,將0011提升為根節點。

​ 2,從圖中可以看出,9的左邊都是比根節點小,9到11之間都是大於9小於11的,最後11的右邊都是大於11的。

​ 3,最後我們再新增5,我們先來分析下結構會如何變化,5小於9,所以會在左邊,變成005006008,這個時候節點數量變成3,根據規則006應該提升為根節點。但是根節點又會變成0060090011,同樣達到閾值,那麼將009再提升為根節點。最終結果如圖:

​ 以上就是B-Tree的原理總結,那麼這與二叉樹有什麼區別呢。最直觀的就是樹的層級變少了,同樣也不會出現左右斜樹的情況。

在InnoDB儲存引擎中有頁(Page)的概念,頁就是磁碟管理的最小單位。InnoDB儲存引擎中預設每個頁的大小為16KB。並且可通過引數innodb_page_size將頁的大小設定為4K、8K、16K。

​ 在B-Tree中,每個節點都會攜帶一個key資訊,用於儲存該資料在表中的位置,同時也會將資料儲存到節點中。當節點不是葉子節點時,父節點會攜帶物件的指標指向其子節點在磁碟中的位置。根據磁碟儲存的頁大小,如果每個葉子節點都攜帶較多的資訊,那麼在磁碟中佔用的空間資源也會越多。顯然這不是一個好的現象,因此就出現B-Tree的優化版,B+Tree。

四,B+Tree

​ InnoDB儲存引擎就是用B+Tree實現其索引結構。

​ 在B+Tree結構中,每一層非葉子節點只儲存key值資訊,而葉子節點只存放資料資訊。這種結構不僅節省磁碟的空間,對節點的查詢效率也大大提高了很多。

​ 除此之外,非葉子節點的key最終會全部出現在葉子節點上, 這麼說很抽象,請看演示效果。

​ 首先新增7,8兩個節點。

​ 接著新增9節點。

​ 同樣度達到了3,將8提升為根節點。但是與B-Tree不同的是,在葉子節點中也存在8節點,這就是B+Tree結構的特點,然後再新增10節點。

​ 以此類推,在最後的葉子節點中,整個樹中的key都在存在,那麼這與B-Tree有什麼區別呢。每個節點中沒有資料儲存,只有key值資訊,在磁碟中會儲存更多的資料。

五,總結

​ 思考一個問題:

​ 對於查詢效率最快的資料結構,雜湊表的效率要比樹狀結構快的多,那麼MySQL儲存引擎為什麼不採用雜湊表結構儲存資料,原因就是雜湊表是不能進行範圍查詢。

​ 本篇部落格並沒有講述對索引使用的優化,只系統闡述了MySQL索引的底層機制,那麼使用索引優化,查詢優化,庫表結構優化會在最後一篇部落格中全部分享完。

​ 以上內容均是自主學習總結,如有錯誤歡迎留言指正。

感謝閱讀