MySQL(十):InnoDB 索引與算法(上篇)

1、簡述

索引是存儲引擎用於快速檢索記錄的的一種數據結構。索引並不是萬能的,在合適的場景使用合適的索引才能真正發揮索引的作用,反之會帶來很糟糕的影響。當數據量較小且負載較低時,添加索引反而多性能造成影響。如果索引太多,反而降低記錄檢索的性能。所以,只有合理的使用索引才能達到我們期望的結果。

很多開發人員往往對數據庫都只是簡單的應用,認爲數據庫的優化交給DBA即可,甚至有些人並不知道索引的存在。那麼怎麼才能合理的使用索引呢?首先清晰正確的認識索引是很有必要的,接下來跟隨筆者由淺入深的認識索引、理解索引,從而正確的使用索引。

2、InnoDB 存儲引擎支持的索引

InnoDB 存儲引擎支持的索引分爲以下幾種,聚集索引(Clustered Indexes)、二級索引(Secondary Index)又稱普通索引、非聚集索引、全文索引(Fulltext Indexes)。

在這裏插入圖片描述

2.1、聚集索引(Clustered Indexes)和 二級索引(Secondary Index)

每個InnoDB表都有一個特殊的索引,稱爲聚簇索引,用於存儲行數據。通常,聚簇索引與主鍵同義。爲了從查詢,插入和其他數據庫操作中獲得最佳性能,很有必要了解InnoDB如何使用聚簇索引爲每個表優化最常見的查找和DML操作。

1、當您在表上定義PRIMARY KEY時,InnoDB會將其用作聚簇索引。如果沒有邏輯唯一且非空的列時,可以添加一個新的自動遞增列作爲主鍵。

2、每個表都有一個主鍵;如果CREATE TABLE沒有指定一個,則使用第一個非NULL唯一鍵,否則,一個6字節隱藏的“行ID”字段會自動添加到表結構中並用作主鍵。

3、“行數據”(非主鍵字段)存儲在主鍵索引結構中,也稱爲“聚集鍵”。該索引結構被存儲到PRIMARY KEY字段中,並且行數據是附加到該鍵的值。

2.2、聚集索引是如何實現快速查詢的

通過聚集索引訪問行是很快的,因爲聚集索引直接指向包含所有行的數據頁 ( data page )。如果表很大,與那種索引頁與數據頁分離的 MyISAM 存儲引擎相比, 聚簇索引體系結構通常可以節省磁盤 I/O 操作。

2.3、二級索引與聚簇索引的關係

除聚集索引以外的所有索引都稱爲輔助索引(二級索引)。在InnoDB中,二級索引中的每個記錄都包含該行的主鍵列以及爲二級索引指定的列。 InnoDB使用此主鍵值在聚集索引中搜索行。

如果主鍵較長,則輔助索引將使用更多空間,因此減小主鍵的長度是有利的。

2.4、全文索引(Fulltext Indexes)

FULLTEXT索引是在基於文本的列(CHAR,VARCHAR或TEXT列)上創建的,以幫助加快對這些列中包含的數據的查詢和DML操作。

FULLTEXT索引定義爲CREATE TABLE語句的一部分,或使用ALTER TABLE或CREATE INDEX添加到現有表中。

可以使用 MATCH() … AGAINST 語法進行全文檢索。

在此不對全文索引深度分析,筆者會另起文章深入分析。

2.5、InnoDB索引的物理結構

除了空間索引(地理位置索引),InnoDB索引都是 B-tree 數據結構。空間索引使用 R-tree, R-tree 是用於索引多維數據的專用數據結構。索引記錄存儲在其B-tree 或 R-tree 數據結構的葉頁中。索引頁的默認大小爲16KB。

當新記錄插入到InnoDB聚集索引中時,InnoDB嘗試使頁面的1/16空閒,以備將來插入和更新索引記錄。如果按順序插入索引記錄(升序或降序),則所得的索引頁約爲15/16。如果以隨機順序插入記錄,則頁面的容量爲1/2到15/16。

InnoDB在創建或重建B樹索引時執行批量加載。這種索引創建方法稱爲排序索引構建。innodb_fill_factor 配置選項定義了在排序索引構建期間填充的每個B樹頁面上的空間百分比,剩餘的空間供將來索引增長使用。空間索引不支持排序索引構建。

如果InnoDB索引頁的填充因子低於MERGE_THRESHOLD,則InnoDB嘗試收縮索引樹以釋放頁面,如果未指定,默認值爲50%。MERGE_THRESHOLD設置適用於B樹索引和R樹索引。

可以通過在初始化MySQL實例之前設置innodb_page_size配置選項來定義MySQL實例中所有InnoDB表空間的頁面大小。一旦定義實例的頁面大小後,如果不重新初始化實例就無法更改它。支持的大小爲64KB,32KB,16KB(默認),8KB和4KB。

有一點需要注意,使用特定InnoDB頁面大小的MySQL實例不能使用來自使用不同頁面大小的實例的數據文件或日誌文件。

在這裏插入圖片描述

頁面結構的主要部分是:

  • FIL頭和尾:這是所有頁面類型的典型和共同之處。對於INDEX頁面而言,在某些方面有些獨特,那就是FIL標頭中的“上一頁”和“下一頁”指針指向同一索引級別的前一頁和後一頁,並根據索引的鍵升序排列。這形成了所有頁面的雙向鏈接列表。

  • INDEX Header:包含許多與INDEX頁和記錄管理相關的字段。下文詳細介紹。

  • FSEG Header:如InnoDB空間文件中的頁面管理中所述,索引根頁面的FSEG標頭包含指向該索引使用的文件段的指針。其他所有索引頁的FSEG標頭均未使用且填充爲零。

  • System Records:InnoDB在每個頁面中都有兩個系統記錄,分別稱爲infimum和supremum。這些記錄存儲在頁面中的固定位置,因此始終可以根據頁面中的字節偏移量直接找到它們。

  • User Records:實際數據。每個記錄都有一個可變寬度的標題和實際的列數據本身。標頭包含“下一條記錄”指針,該指針以升序存儲到頁面中下一條記錄的偏移量,從而形成一個單鏈接列表。用戶記錄結構的詳細信息將在以後的文章中進行描述。

  • Page Directory:頁面目錄從頁面的“頂部”開始向下擴展,從FIL尾部開始,並且包含指向頁面中某些記錄的指針(每4至8條記錄)。

2.6、排序索引構建

在創建或重建索引時,InnoDB執行批量加載,而不是一次插入一個索引記錄。這種索引創建方法也稱爲排序索引構建。空間索引不支持排序索引構建。

索引構建有三個階段:

  • 第一階段,將掃描聚簇索引,並生成索引條目並將其添加到排序緩衝區。當排序緩衝區已滿時,將對條目進行排序並將其寫到臨時中間文件中。此過程也稱爲“run”。

  • 第二階段,將一個或多個“run”寫入臨時中間文件,對文件中的所有條目執行合併排序。

  • 第三個階段,將已排序的條目插入到 B 樹中

在引入排序索引構建之前,使用插入API將索引條目一次插入到B樹中的一條記錄中。該方法涉及打開B樹光標以找到插入位置,然後使用樂觀插入將條目插入B樹頁面。如果由於頁面已滿而導致插入失敗,則將執行悲觀插入,這涉及打開B樹遊標並根據需要拆分和合並B樹節點以找到條目空間。這種建立索引的“自上而下”方法的缺點是搜索插入位置的成本以及B樹節點的不斷拆分和合並的成本。

排序索引的構建使用“自下而上”的方法來構建索引。通過這種方法,在B樹的所有級別都保留了對最右邊的葉子頁的引用。在必要的B樹深度處分配最右邊的葉子頁,並根據其排序順序插入條目。葉子頁已滿後,節點指針將附加到父頁,並且爲下一個插入分配同級葉子頁。此過程將一直持續到插入所有條目爲止,這可能會導致插入到根級別。分配同級頁面後,將釋放對先前固定的葉子頁面的引用,並且新分配的葉子頁面將成爲最右邊的葉子頁面和新的默認插入位置。

2.6.1、爲將來的索引增長保留B-tree頁面空間

要爲將來的索引增長留出空間,可以使用 innodb_fill_factor 配置選項保留一定比例的B樹頁面空間。例如,將innodb_fill_factor設置爲80可以在排序索引構建期間在B樹頁面中保留20%的空間。此設置適用於B樹葉子頁面和非葉子頁面。它不適用於用於TEXT或BLOB條目的外部頁面。保留的空間量可能與配置不完全一樣,因爲innodb_fill_factor值被解釋爲提示而不是硬限制。

2.6.2、排序索引構建和全文本索引支持

全文索引支持排序索引構建。以前,SQL是用於將條目插入全文索引的。

2.6.3、排序索引構建和壓縮表

對於壓縮表,以前的索引創建方法將條目附加到壓縮和未壓縮頁面上。當修改日誌(表示壓縮頁面上的可用空間)已滿時,將重新壓縮壓縮頁面。如果由於空間不足而導致壓縮失敗,則將拆分頁面。使用排序索引構建時,條目僅追加到未壓縮的頁面。當未壓縮的頁面已滿時,它將被壓縮。自適應填充用於確保大多數情況下壓縮成功,但是如果壓縮失敗,則會拆分頁面並再次嘗試壓縮。該過程一直持續到壓縮成功爲止。

2.6.4、排序索引構建和重做日誌記錄

在排序索引構建期間,重做日誌記錄被禁用。而是有一個檢查點來確保索引構建可以承受崩潰或失敗。該檢查點強制將所有髒頁寫入磁盤。在排序索引的構建過程中,頁面清潔器線程會定期發出信號以刷新髒頁面,以確保可以快速處理檢查點操作。通常,當清潔頁數低於設置的閾值時,頁面清潔程序線程將刷新髒頁。對於排序的索引生成,髒頁將立即刷新,以減少檢查點開銷並並行化I / O和CPU活動。

2.6.5、排序索引構建和優化器統計

排序的索引構建可能會導致優化器統計信息與以前的索引創建方法所生成的統計信息不同。統計信息的差異(預計不會影響工作負載性能)是由於用於填充索引的算法不同。

3、參考文獻

  1. 《高性能MySQL(第3版)》
  2. 《MySQL技術內幕:InnoDB存儲引擎(第2版)》
  3. 《MySQL源碼庫》
  4. 《MySQL參考手冊》
  5. 《MySQL實戰45講》
  6. 《數據庫內核月報》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章