1. 程式人生 > MYSQL進階教學 ><p>B-Tree 索引型別詳解</p>

<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 索引的查詢型別和相關限制,從中我們可以看出,索引列的順序非常重要。在某些應用場景,可能需要建立相同列,但順序不同的索引,來滿足效能的優化。