<p>B-Tree 索引型別詳解</p>
索引有很多種型別,可以為不同的應用場景提供更好的效能。在 MySQL 中,索引是在儲存引擎層實現的。接下來重點介紹四種常見的索引型別:B-Tree 索引、雜湊索引、空間資料索引(R-Tree)、全文索引。這部分內容分為上下兩個小節,本小節重點介紹 B-Tree 索引。
1. B-Tree 索引
B-Tree 索引是最常見的索引之一,當大家在談論索引的時候,如果沒有特別說明,那多半說的就是 B-Tree 索引。在 MySQL 中,大多數的儲存引擎都支援 B-Tree 索引。
1.1 儲存結構
B-Tree 對索引列的值是按順序儲存的,並且每一個葉子頁到根的距離相同。B-Tree 索引可以加快資料查詢的速度,因為儲存引擎不需要全表掃描來獲取資料,只要從索引的根節點開始搜尋即可。
以表 customer 為例,我們來看看索引是如何組織資料的儲存的。
mysql> create table customer(
id int,
last_name varchar(30),
first_name varchar(30),
birth_date date,
gender char(1),
key idx1_customer(last_name,first_name,birth_date)
);
如圖,對於表中的每行資料,索引包含了 last_name、first_name 和 birth_date 的值。
1.2 適合 B-Tree 索引的查詢型別
全值匹配
和索引中的所有列進行匹配,如查詢姓名為 George Bush、1960-08-08 出生的客戶。
mysql> explain select * from customer where first_name='George' and last_name='Bush' and birth_date='1960-08-08'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: ref
possible_keys: idx1_customer
key: idx1_customer
key_len: 190
ref: const,const,const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
匹配最左字首
只使用索引的第一列,如查詢所有姓氏為 Bush 的客戶:
mysql> explain select * from customer where last_name='Bush'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: ref
possible_keys: idx1_customer
key: idx1_customer
key_len: 93
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
匹配列字首
只匹配某一列的值的開頭部分,如查詢所有以 B 開頭的姓氏的客戶,這裡使用了索引的第一列:
mysql> explain select * from customer where last_name like 'B%'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: range
possible_keys: idx1_customer
key: idx1_customer
key_len: 93
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
匹配範圍值
查詢所有姓氏在 Allen 和 Bush 之間的客戶,這裡使用了索引的第一列:
mysql> explain select * from customer where last_name between 'Allen' and 'Bush'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: range
possible_keys: idx1_customer
key: idx1_customer
key_len: 93
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
精確匹配某一列,並範圍匹配另一列
第一列全匹配,第二列範圍匹配,如查詢姓氏為 Bush,名字以 G 開頭的客戶:
mysql> explain select * from customer where last_name='Bush' and first_name like 'G'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: range
possible_keys: idx1_customer
key: idx1_customer
key_len: 186
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
只訪問索引的查詢
只需要訪問索引即可獲取資料,不需要回表訪問資料行,這種查詢也叫覆蓋索引:
mysql> explain select last_name from customer where last_name='Bush'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: ref
possible_keys: idx1_customer
key: idx1_customer
key_len: 93
ref: const
rows: 1
filtered: 100.00
Extra: Using index
1 row in set, 1 warning (0.00 sec)
除了上述這些查詢型別外,索引還可以用於 order by 排序操作,因為索引中的節點是有序的。如果 B-Tree 可以按照某種方式查詢到資料,那麼也可以按照這種方式進行排序。
1.3 B-Tree 索引的限制
如果不是按照索引的最左列開始查詢資料,則無法使用索引。如查詢名字為 George 的客戶:
mysql> explain select * from customer where first_name='George'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
不能跳過索引的列。如查詢姓氏為 Bush,生日為 1960-08-08 的客戶,這種查詢只能使用索引的第一列:
mysql> explain select * from customer where last_name='Bush' and birth_date='1960-08-08'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: ref
possible_keys: idx1_customer
key: idx1_customer
key_len: 93
ref: const
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
如果查詢中有某個列的範圍查詢,在其右邊的列都無法使用索引進行查詢資料。如查詢姓氏為以 B 開頭,名字為 George 的客戶。這個查詢只能使用第一列,因為 like 是一個範圍查詢:
mysql> explain select * from customer where last_name like 'B%' and first_name='George'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: customer
partitions: NULL
type: range
possible_keys: idx1_customer
key: idx1_customer
key_len: 186
ref: NULL
rows: 1
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
2. 小結
本小節介紹了 B-Tree 索引的儲存結構、適合 B-Tree 索引的查詢型別和相關限制,從中我們可以看出,索引列的順序非常重要。在某些應用場景,可能需要建立相同列,但順序不同的索引,來滿足效能的優化。