MysQL B-Tree 索引

B-Tree 索引
不一樣的存儲引擎也可能使用不一樣的存儲結構,i如,NDB集羣存儲引擎內部實現使用了T-Tree結構存儲這種索引,即便其名字是BTREE;InnoDB使用的是B+Tree。html

B-Tree一般一位這全部的值都是按順序存儲的,而且每個葉子頁道根的距離相同。下圖大體反應了InnoDB索引是如何工做的。
image.pngmysql

爲何mysql索引要使用B+樹,而不是B樹,紅黑樹
看完上面的文章就能夠理解爲什麼B-Tree索引可以快速訪問數據了。由於存儲引擎再也不須要進行全表掃描獲取須要的數據,葉子節點包含了全部元素信息,每個葉子節點指針都指向下一個節點,因此很適合查找範圍數據。sql

索引對多個值進行排列的依據是CREATE TABLE 語句中定義索引時的順序。segmentfault

那麼,索引排序的規則就是按照 last_name ,first_name ,dob 的順序來的。性能

可使用 B-Tree 索引的查詢類型
B-Tree索引適用於全鍵值、鍵值範圍或鍵前綴查找。
鍵前綴查找只是用於根據最左前綴查找。mysql索引

舉個粒子:優化

CREATE TABLE People (
    last_name VARCHAR ( 50 ) NOT NULL,
    first_name VARCHAR ( 50 ) NOT NULL,
    dob date NOT NULL,
    gender enum ( 'm', 'f' ) NOT NULL,
KEY ( last_name, first_name, dob ) 
);

這個表的索引以下:
image.pngspa

type結果指針

type結果值從好到壞依次是:code

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

通常來講,得保證查詢至少達到range級別,最好能達到ref,不然就可能會出現性能問題。

possible_keys:sql所用到的索引

key:顯示MySQL實際決定使用的鍵(索引)。若是沒有選擇索引,鍵是NULL

(1)全值匹配

全值匹配指的是和索引中的全部列進行匹配。

例如上面的People表的索引(last_name,first_name,dob)能夠用於查找last_name=’Cuba Allen’,first_name=’Chuang’,dob=’1996-01-01’的人。這就是使用了索引中的全部列進行匹配,即全值匹配。

mysql> EXPLAIN select * from People where last_name = 'aaa' and first_name = 'bbb' and dob='2020-11-20' \G;
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: People
  partitions: NULL
        type: ref
possible_keys: last_name
         key: last_name    <-----能夠看到這個key就是咱們定義的索引
     key_len: 307
         ref: const,const,const
        rows: 1
    filtered: 100.00
       Extra: NULL
1 row in set, 1 warning (0.00 sec)

ERROR: 
No query specified

(2)匹配最左前綴

能夠只使用索引的第一個列進行匹配。

例如能夠用於查找last_name=’aaa’的人,即用於查找姓爲aaa的人,這裏只使用了索引的最左列進行匹配,即匹配最左前綴。

mysql> EXPLAIN select * from People where last_name = 'aaa'  \G;
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: People
  partitions: NULL
        type: ref
possible_keys: last_name
         key: last_name    <----使用了索引
     key_len: 152
         ref: const
        rows: 3
    filtered: 100.00
       Extra: NULL
1 row in set, 1 warning (0.00 sec)

ERROR: 
No query specified

(3)匹配列前綴

能夠只匹配某一列的值的開頭部分。

例如能夠用於查找last_name LIKE ‘a%’的人,即用於查找全部以a開頭的姓的人,這裏只使用了索引最左列的前綴進行匹配,即匹配列前綴。

mysql> EXPLAIN select * from People where last_name = 'a%'  \G;
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: People
  partitions: NULL
        type: ref
possible_keys: last_name
         key: last_name      <---使用了索引
     key_len: 152
         ref: const
        rows: 1
    filtered: 100.00
       Extra: NULL
1 row in set, 1 warning (0.00 sec)

ERROR: 
No query specified

(4)匹配範圍值

能夠只適用索引的第一列查找符合某個範圍內的數據。

例如能夠用於查找last_name BETWEEN ‘aaa’ AND ‘aaabbbccc’的人,即用於查找姓在aaa和aaabbbccc之間的人,這裏只使用了索引最左列的前綴進行範圍匹配,即匹配範圍值。

mysql> EXPLAIN select * from People where  last_name BETWEEN 'aaa' and 'aaabbbccc'\G;
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: People
  partitions: NULL
        type: range
possible_keys: last_name
         key: last_name    <---使用了索引
     key_len: 152
         ref: NULL
        rows: 3
    filtered: 100.00
       Extra: Using index condition
1 row in set, 1 warning (0.00 sec)

ERROR: 
No query specified

(5)精確匹配某一列並範圍匹配另一列

可使第一列全匹配,第二列範圍匹配。

例如能夠用於查找last_name=’aaa’ AND first_name LIKE ’b%’的人,即用於查找姓是aaa,名字以b開頭的人,這裏使用了索引的最左列精確匹配,第二列進行範圍匹配。

mysql> EXPLAIN select * from People where  last_name = 'aaa' and first_name like 'b%'\G;
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: People
  partitions: NULL
        type: range
possible_keys: last_name
         key: last_name    <---使用了索引
     key_len: 304
         ref: NULL
        rows: 1
    filtered: 100.00
       Extra: Using index condition
1 row in set, 1 warning (0.00 sec)

ERROR: 
No query specified

(6)只訪問索引的查詢

查詢只需訪問索引,而無須訪問數據行。

例如select last_name, first_name where last_name=’aaa’; 這裏只查詢索引所包含的last_name和first_name列,則無須讀取數據行。

mysql> explain select last_name,first_name,dob from People where last_name = 'aaa'
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: People
   partitions: NULL
         type: ref
possible_keys: last_name
          key: last_name
      key_len: 152
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)

ERROR: 
No query specified

另外,索引還能夠用於查詢中的order by 操做。若是order by 子句知足前面列出的集中查詢類型,則這個索引也能夠知足對應的排序需求。

B-Tree 的限制

1)只能按照索引的最左列開始查找。

例如People表中的索引沒法用於查找first_name爲’bbb’的人,也沒法查找某個特定生日的人,由於這兩個列都不是最左數據列。

(2)只能按照索引最左列的最左前綴進行匹配。

例如People表中的索引沒法查找last_name LIKE ‘%b’的人,雖然last_name就是此索引的最左列,但MySQL索引沒法查找以‘b’結尾的last_name的記錄。

(3)只能按照索引定義的順序從左到右進行匹配,不能跳過索引中的列。

例如People表中的索引沒法用於查找last_name=’a’ AND bod=’1996-01-01’的人,由於MySQL沒法跳過索引中的某一列而使用索引中最左列和排在末尾的列進行組合。若是不指定索引中中間的列,則MySQL只能使用索引的最左列,即第一列。

(4)若是查詢中有某個列的範圍查詢,則其右邊全部列都沒法使用索引優化查找。

例若有這樣一個查詢:where last_name=’a’ AND first_name LIKE ’b%’ AND dob=’1996-01-01’; 這個查詢只能使用索引的前兩列,由於這裏LIKE是一個範圍條件,則first_name後面的索引列都將失效。(優化點:儘可能不要在索引列中使用LIKE等範圍條件,改用多個等於條件來替代,保證後面的索引列能生效。)

MysQL EXPLAIN 詳解

如何查看sql查詢是否用到索引(mysql)

參考書籍:高性能MySQL

相關文章
相關標籤/搜索