MySQL核心:索引結構原理

MySQL核心:索引結構原理

數據庫的索引就像一本書的目錄一樣,它可以快速定位你所需要的信息。下面來詳細說一下MySQL的索引結構。

常見索引類型

Hash 索引

Hash索引的底層實現是由Hash表來實現的,非常適合以 key-value 的形式查詢,也就是單個key 查詢,或者說是等值查詢。其結構如下所示:

MySQL核心:索引結構原理

從上面結構可以看出,Hash 索引可以比較方便的提供等值查詢的場景。但是對於範圍查詢的話,就需要進行全表掃描了。

B+ 索引

Hash結構的索引比較適合緩存的存儲。對於使用關係型數據庫而言,筆者更多的使用的是B+ 索引。當然對於MySQL 我們最常用的存儲引擎就是InnoDB 了,對於B+ 索引後面將詳細介紹一下。

InnoDB 的索引結構

首先先創建一個簡單的表,結構如下:

CREATE TABLE `t_user` (
 `id` bigint(20) NOT NULL COMMENT '主鍵ID',
 `age` int(10) DEFAULT NULL COMMENT '年齡',
 PRIMARY KEY (`id`),
 KEY `idx_age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT INTO `t_user` VALUES ('100', '10'), ('200', '20'), ('300', '30'), ('500', '50'), ('600', '60');

上面表和數據的存儲結構大致如下所示:

MySQL核心:索引結構原理

從上圖可以看出,有 2 個索引結構:主鍵ID 索引和普通索引。主鍵索引的葉子節點存儲的是行數據的內容(聚簇索引),普通索引的葉子節點存儲的是主鍵的值(非聚簇索引/二級索引)。

主鍵索引和普通索引的區別

當我們使用主鍵索引查詢記錄時,查詢語句如下所示。此時只需要一次主鍵索引樹的查找即可返回數據行。

SELECT * FROM t_user WHERE id = 100;

如果使用普通索引,idx_age 查詢記錄,如下所示。此時就會查找2 個索引樹的結構。首先根據idx_age 查找到記錄的主鍵值為 100,然後再根據主鍵索引樹查找到對應的記錄行,這個過程稱為回表。

SELECT * FROM t_user WHERE age = 10;

索引維護

B+ 樹為了維持索引的有序性,在新插入記錄時需要有一定的開銷。如上圖所示,如果需要再插入一個id = 700 的記錄行,此時只需要在 User5 後面新增一條記錄即可。但是如果需要新增一個 id = 400 的記錄行時,此時就需要移動數據了,這個和有序數組的插入類似。

比較極端的一種場景是,此時User5 所在的數據頁已經滿了。此時如果再插入一條記錄,就需要移動部分數據行到新頁上面去。這種情況下,性能會受到一定的影響。除此之外,頁分裂還存在著空間利用率的問題。

當然,有頁分裂就有數據頁的合併,當空間利用率低到一定程度的時候,就會觸發分頁數據的合併。

主鍵ID自增

從上面的描述我們可以看出,主鍵ID的亂序插入或者刪除可能對性能造成很大的影響。這就是為什麼,我們在大多數場景下對於主鍵都是自增的。這樣一來,就可以充分的利用分頁數據塊的空間了,也不會對性能造成影響。

覆蓋索引

上面我們已經提到了 回表的概念了,也就是普通索引的查詢,可能會再到主鍵索引上面再搜索一遍。但是如果我們執行如下語句:

SELECT id FROM t_user WHERE age = 10;

此時,普通索引 idx_age 的葉子節點上面,就已經包含了id 的value值了,此時就不需要回表了,這個就稱之為“覆蓋索引”(覆蓋索引是一種優化查詢的方式,不是索引的分類)。

聯合索引

我們創建索引時,也會經常創建如 idx_name_age (name, age) 這樣的索引結構。並且還知道 WHERE 條件中 name = ? AND age = ? 和 name = ? 都可以使用到這個聯合索引。下面我們來看一下其結構,看一下為什麼是可以做到這一點的。

MySQL核心:索引結構原理

從上面結構可以看出,數據是按照 聯合索引 從左到右的順序進行排序的。由此看來,不論使用 name AND age 或者name 來查詢,不論等值或者 左前綴模糊查詢,都可以用到複合索引。這裡面需要注意的是,只有左前綴的模糊匹配才可以使用此聯合索引。因為從索引結構看來,符合左前綴的順序排序。

索引下推

前面的部分我們知道,左前綴的模糊查詢可以使用索引。還是上面的例子,索引(name, age) ,當我們 WHERE條件中使用 name LIKE '張%' AND age = 10 時。MySQL 5.6 及以後的版本可以對查詢做下推的優化,如下圖所示:

MySQL核心:索引結構原理

MySQL核心:索引結構原理

從上圖可以看出,當做了下推優化後,MySQL會隔斷一些不滿足條件的記錄 進行回表操作,從一定程度上有了性能的提升。

參考:《極客時間:MySQL實戰》、《高性能MySQL》


分享到:


相關文章: