# 《MySQL技術內幕-InnoDB存儲引擎》整理4-索引與算法

一、InnoDB存儲引擎索引概述

InnoDB存儲引擎支持以下幾種常見的索引:①B+樹索引;②全文索引;③哈希索引

InnoDB存儲引擎支持的哈希索引是自適應的,InnoDB存儲引擎會根據表的使用情況自動爲表生成哈希索引,不能人爲干預是否在一張表中生成哈希索引。B+樹索引就是傳統意義上的索引,B+樹索引的構造類似於二叉樹,根據鍵值快速找到數據(B不是代表二叉二而是代表平衡),並且B+樹索引找到的只是被查找數據行所在的頁,然後將頁讀到內存中,在內存中進行查找直至找到數據

二、數據結構與算法

1、二分查找法

基本思想是:將記錄按有序化排列,在查找過程中採用跳躍式方法查找,即先以有序數列中的中間位置爲比較對象,如果要查找的元素值小於該中點元素,則將帶查找序列縮小爲左半部分,否則爲右半部分

2、二叉查找樹和平衡二叉樹(AVL樹)

在二叉查找樹中,左子樹的鍵值總是小於根的鍵值,右子樹的鍵值總是大於根的鍵值,可以通過中序遍歷得到鍵值的排序輸出。但若想最大性能的構造出一顆二叉查找樹,需要這顆二叉查找樹是平衡的。

平衡二叉樹的定義:首先符合二叉查找樹的定義,其次滿足任何節點的兩個子樹的高度最大差爲1。平衡二叉樹的查找性能較高,但不是最好的,最好性能的查找樹爲最優二叉樹。

3、B+樹

B+樹由B樹和索引順序訪問方法演化而來,簡單來說,B+樹是爲磁盤或其他直接存取輔助設備設計的一種平衡查找樹。在B+樹中,所有記錄節點都是按照鍵值的大小順序放在同一層的葉子節點上,由各葉子節點指針進行連接

1、B+樹的插入操作

B+樹的插入操作必須保證插入後葉子節點中的記錄依然排序,同時需要考慮插入到B+樹的三種情況導致的不同插入算法:

  • 葉子頁仍有空間,索引頁仍有空間的情況下,直接將記錄插入到葉子節點
  • 葉子頁沒有空間,索引頁仍有空間的情況下,拆分葉子頁,將中間的節點放入索引頁中,小於中間節點的記錄方左邊,大於等於中間節點的記錄方右邊
  • 葉子頁沒有空間,索引頁沒有空間的情況下,拆分葉子頁,小於中間節點的記錄放左邊,大於等於中間節點的記錄放右邊,拆分索引頁,小於中間節點的記錄放左邊,大於中間節點的記錄放右邊,中間節點放入上一層Index Page

此外爲了保持平衡對於新插入的鍵值可能需要做大量的拆分頁的操作,B+樹提供了類似平衡二叉樹的旋轉功能。當葉子頁已滿,但是其左右兄弟節點未滿,會將記錄轉移到兄弟節點上

2、B+樹的刪除操作

B+樹使用填充因子來控制樹的刪除變化,50%是可設定的最小值,B+樹的刪除操作同樣必須保證刪除後葉子節中的記錄依然排序,B+樹的刪除操作需要考慮三種情況,同時結合填充因子的變化來衡量:

  • 葉子節點大於等於填充因子,且中間節點小於填充因子時,直接將記錄從葉子節點刪除,如果該節點是索引頁的節點,用該節點的右節點代替
  • 葉子節點小於填充因子,且中間節點小於填充因子時,合併葉子節點和它的兄弟節點,同時更新索引頁
  • 葉子節點大於等於填充因子,且中間節點大於等於填充因子時,合併葉子節點和它的兄弟節點,更新索引頁,合併索引葉和它的兄弟節點

4、B+樹索引

B+樹索引的本質就是B+樹在數據庫中的實現,B+索引在數據庫中的特點是高扇出性,樹的高度一般在2~4層。數據庫中的B+樹索引分爲聚集索引和輔助索引,其區別是葉子節點存放的是否是一整行的信息

1、聚集索引

聚集索引是按照每張表的主鍵構造的一顆B+樹,同時葉子節點存放的即爲整張表的行數據,也稱爲數據頁,另外索引組織表中的數據也是索引的一部分。聚集索引非物理上連續,而是邏輯上連續,它們通過雙向鏈表鏈接,頁按照主鍵的順序排序。

2、輔助索引

對於輔助索引,葉子節點不包含行記錄的全部數據,葉子節點除了包含鍵值書籤,每個葉子節點中的索引行還包含了一個書籤,該書籤用來告訴InnoDB存儲引擎哪裏可以找到與索引相對應的行數據。由於InnoDB存儲引擎表是索引組織表,因此InnoDB存儲引擎的輔助索引的書籤就是相應行數據的聚集索引鍵。

3、B+樹索引的分裂

B+樹索引頁的分裂並不總是從頁的中間記錄開始,這樣會導致空間的浪費。InnoDB存儲引擎的Page Header中來保存插入的Page_Last_Insert、Page_Direction、Page_N_Direction來保存順序信息,並通過它們來決定是向左分裂還是向右分裂,同時決定分裂點記錄爲哪一個

4、B+樹索引的管理

1、索引管理

索引的創建和刪除可以通過兩種方法,一種是Alter Table,另一種是Create/Drop Index。用戶可以對整個列的數據進行索引,也可以只索引列開頭的部分數據,可以通過Show Index From xxx命令可以查看索引的信息。

2、Fast Index Creation

Fast Index Creation即快速索引創建,對於輔助索引的創建,InnoDB存儲引擎會對創建索引的表加上一個S鎖,可以併發地讀事務。對於輔助索引的刪除,InnoDB存儲引擎只需要更新內部視圖,並將輔助索引的空間標記爲可用,同時刪除MySql數據庫內部視圖上對該表的索引定義。

3、Online Schema Change

Online Schema Change即在線架構改變,在線是指在事務的創建過程中,可以有讀寫事務對錶進行操作,以提高原有Mysql數據庫在DDL操作時的併發性。

4、Online DDL

Mysql5.6開始支持Online DDL操作,允許輔助索引創建的同時,還允許DML操作,極大的提高了Mysql數據庫在生產環境中的可用性。此外可以使用Alter Table語法選擇索引的創建方式:

  • Copy表示按照創建臨時表的方式創建索引
  • Inplace表示索引創建或刪除操作不需要創建臨時表
  • Default表示根據old_alter_table來判斷是通過Inplace還是Copy,該參數默認未Off,表示採用Inplace方式

創建索引中的Lock部分爲索引創建或刪除時對錶添加鎖的情況:

  • None表示執行索引創建或刪除操作時,對目標表不添加任何鎖,即事務可以進行讀寫操作,不會收到阻塞,支持最大的併發度;
  • Share表示執行索引的創建過刪除操作時,對目標表加一個S鎖,支持併發地讀事務,遇到寫事務會等待
  • Exclusive表示執行索引創建或刪除操作時,對目標表加上一個X鎖,讀寫事務都不能進行,因此會阻塞所有的線程
  • Default表示首先會判斷當前操作是否可以使用None模式,若不能則判斷是否可以使用Share模式,最後判斷是否可以使用Exclusive模式

5、Cardinality值

1、什麼是Cardinality

不是所有查詢條件中出現的列都需要添加索引,當某個字段的取值範圍很廣,機會沒有重複時即屬於高選擇性,此時使用B+樹索引是最合適的,如何查看索引是否是高選擇性的,通過Show Index結果中的Cardinality列可以知曉,它表示所重複記錄數量的預估值,理論情況下它與行數據的比例應該儘可能的接近1

2、InnoDB存儲引擎的Cardinality統計

數據庫對於Cardinality的統計是在引擎層進行的,通過採樣方式完成。其統計發生在兩個操作中,Insert和Update,當表中1/16的數據發生變化後會進行更新,或者對錶中某一行的數據頻繁地進行更新操作時,即當更新統計參數stat_modified_counter大於2000000000時,同樣會更新Cardinality信息

6、B+樹索引的使用

1、不同應用中B+樹索引的使用

對於OLTP應用,即查詢一小部分數據時,對索引的使用則是通過索引取得表中少部分的數據。對於OLAP應用,較爲複雜的查詢涉及表的關聯查詢,此時索引的添加依舊是有意義的

2、聯合索引

聯合索引是指對錶上多個列進行索引,聯合索引也是一顆B+樹,不同的是聯合索引的鍵值的數量不是1而是大於等於2的。對於(a,b)類型的聯合索引,對於單個的a列查詢同樣可以使用該聯合索引。此外它的另一個好處是已經對第二個鍵值進行了排序處理。

3、覆蓋索引

InnoDB存儲引擎支持覆蓋索引,即從輔助索引中就可以得到查詢的記錄,而不需要查詢聚集索引中的記錄,此外覆蓋索引的好處是輔助索引不包含整行記錄的所有信息,其大小遠小於聚集索引,可以減少大量的IO操作。此外針對一些統計查詢,也可以減少部分IO操作

4、優化器選擇不使用索引的情況

在某些情況下,優化器會選擇掃描聚集索引查找數據,即全表掃描,這類情況多發生於範圍查找和Join鏈接操作。當訪問數據佔整個表的20%時,優化器會選擇聚集索引來查找數據

5、索引提示

Mysql數據庫支持顯示地告訴優化器使用哪個索引,以下兩種情況下需要使用索引提示(Index Hint):

  • Mysql數據庫優化器錯誤地選擇了某個索引,導致SQL執行很慢
  • 某SQL語句可以選擇的索引非常多,優化器執行計劃時間的開銷大於SQL語句本身

6、Multi-Range Read優化

Mysql5.6版本開始支持Multi-Range Read(MRR)優化,其目的是爲了減少磁盤的隨機訪問,並且將隨機訪問轉換爲較爲順序的數據訪問,對於IO-bound類型的SQL查詢語句帶來極大的提升,此外可以並減少緩衝池中頁被代替的次數,並批量處理對鍵值的查詢操作。

對於InnoDB和MyISAM存儲引擎的範圍查詢和Join查詢操作,MRR的工作方式如下:

  • 將查詢得到的輔助索引值存放於一個緩存中,且緩存中的數據是根據輔助索引鍵值排序的
  • 將緩存中的鍵值根據RowID進行排序
  • 根據RowID的排序順序來訪問實際的數據文件

此外啓用Multi-Range Read還可以將某些範圍的查詢拆分爲鍵值對,來進行批量的查詢,而非查詢出來一部分後再進行過濾

7、Index Confition Pushdown優化

一般情況下在進行索引查詢時,會更加索引來查找數據,然後再根據Where條件來過濾記錄,而在Mysql5.6支持Index Confition Pushdown以後,Mysql數據庫會在去除索引的同時,判斷是否可以進行Where條件的過濾,在某些情況下,可以大大減少上層SQL層對記錄的fetch,從而提高性能

7、哈希算法

1、哈希表

哈希表也稱散列表,由直接尋址表改進而來,在該方式下可以根據關鍵字計算出槽的位置,再利用哈希函數h可以將關鍵字域銀蛇到哈希表的槽位上。

對於哈希碰撞問題,數據庫一般採用的技術稱爲鏈接法。鏈接法會將散列到同一槽中的所有元素放在一個鏈表中。對於哈希函數,數據庫一般採用除法散列實現,如將關鍵字映射到m個槽的某一個去,則通過k mod m得到餘數

2、InnoDB存儲引擎中的哈希算法

InnoDB存儲引擎中採用哈希算法對字典進行查找,其衝突機制採用鏈表方式,哈希函數採用除法散列方式。m的取值爲略大於2倍的緩衝池頁數量的質數。

3、自適應哈希索引

自適應哈希索引由數據庫自身創建並使用,經哈希函數映射到一個哈希表中,對於字典的查找非常快速,但是對於範圍查找無能爲力

8、全文檢索

1、概述

全文檢索是將存儲於數據庫中的整本書或者整篇文章中的任意內容信息查找出來的技術,它可以根據需要獲得全文中所有的有關章、節、段、句、詞等信息,也可以進行各種統計和分析

2、倒排索引

全文索引通常使用倒排索引實現,倒排索引和B+樹索引一樣也是一種索引結構,它在輔助表中存儲了單詞與單詞自身在一個或多個文檔中所在位置之間的映射。其通常利用關聯數組實現,擁有兩種表現形式:

  • inverted file index,表現形式爲{單詞,單詞所在文檔的ID}
  • full inverted index,其表現形式爲{單詞,(單詞所在文檔的ID,在具體文檔中的位置)}

3、InnoDB全文檢索

InnoDB存儲引擎從1.2.x版本開始支持全文檢索的技術,採用full inverted index方式,(DocumentId,Postion)被視爲一個ilist,因此在全文檢索的表中,有兩個列,一個是Word字段,另一個是ilist字段,Word字段上設有索引。

倒排索引需要將word存放在一張表中,這個表稱爲輔助表,InnoDB共有6個輔助表,並且持久化地存放在磁盤上,此外InnoDB還用到了FTS Index Cache全文檢索索引緩存,用來提高全文檢索的性能。它是一個紅黑樹結構,根據(word,ilist)進行排序。InnoDB會批量對輔助表進行更新,而不是每次插入後更新一次輔助表。

當前InnoDB存儲引擎的全文索引還存在以下限制:

  • 每張表只能有一個全文檢索的索引
  • 由多列組合而成的全文檢索的索引列必須使用相同的字符集與排列規則
  • 不支持沒有單詞界定符的語言,如中文、日語、韓語

4、全文檢索

Mysql支持全文檢索的查詢,其語法爲Mactch()...Against()語法支持全文檢索的查詢,Match指定了需要被查詢的列,Against指定了使用何種方法去進行查詢,下面介紹查詢模式

1、Natural Language

全文檢索通過Match函數進行查詢,默認採用Natural Language模式,其表示查詢帶有指定word的文檔,如通常使用的select * from tableA where body like '%xx%',若使用全文檢索技術,可以使用select * from tableA where Match(body) Against('xx')

Where條件中的使用Match函數,查詢返回的結果是根據相關性進行排序的,相關性最高的結果放在第一位,其計算依據如下:1).word是否在文檔中出現;2).word在文檔中出現的次數;3).word在索引中列的數量;4).多少個文檔包含該word

2、Boolean

Mysql數據庫允許使用In Boolean Mode修飾符來進行全文的檢索,Boolean全文檢索支持以下幾種操作符:

  • +表示該word必須存在
  • -表示該word必須被排除
  • (no operator)表示該word是否是可選的,如果出現,相關性會更高
  • @distance表示查詢的多個單詞之間的距離是否在distance之內,其單位是字節
  • >表示出現該單詞時增加相關性
  • <表示出現該單詞時降低相關性
  • ~表示允許出現該單詞,但是出現時相關性爲負
  • *表示以該單詞開頭的單詞
  • ''表示短語
3、Query Expansion

Mysql數據庫支持全文檢索的擴展查詢,此類查詢在查詢的關鍵詞太短,用戶需要隱含知識時進行。通過在查詢短語中添加With Query Expansion或者In Natural Language Mode With Query Expansion可以開啓blind query expansion。該查詢分爲兩個階段:

  • 第一階段:根據搜索的單詞進行全文索引查詢
  • 第二階段:根據第一階段產生的分詞再進行一次全文檢索的查詢
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章