1. 程式人生 > >資料庫索引-B-Tree索引

資料庫索引-B-Tree索引

1.索引簡介

索引(鍵(key))是儲存引擎用於快速找到記錄的一種資料結構。索引對於良好的效能非常關鍵。索引優化應該是對查詢效能優化最有效的手段了,索引能夠輕易將查詢效能提高几個數量級,“最優”的索引有時比一個“好的”索引效能要好兩個數量級。建立一個真正“最優”的索引經常需要重寫查詢。

索引類似書的目錄。在MySql中,儲存引擎用類似的方法使用索引,其先在索引中找到對應值,然後根據匹配的索引記錄找到對應的資料行。例子:

mysql>SELECT first_name FROM sakila.actor WHERE actor_id=5;

如果在actor_id列上建有索引,則MySQL將使用該索引找到actor_id為5的行,也就是說,MySQL先在索引上按值進行查詢,然後返回所有包含該值的資料行。

索引可以包含一個或多個列的值,如果索引包含多個列,那麼列的順序也十分重要。因為MySQL只能高效地使用索引的最左字首列。建立一個包含兩個列的索引和建立兩個只包含只包含一列的索引是大不相同的。

2.索引的型別

MySQL中,索引是在儲存引擎層而不是伺服器層實現的。不同儲存引擎的索引的工作方式不一樣,也不是所有儲存引擎都支援所有型別的索引。即使多個儲存引擎支援同一個型別的索引,其底層實現也可能不同。

下面介紹MySQL支援的索引型別,以及它們的優點和缺點。

B-Tree索引

當人們談論索引的時候,如果沒有特別指明型別,那多半說的是B-Tree索引,它使用B-Tree資料結構來儲存資料。大多數MySQL引擎支援這種索引。

B-Tree通常意味著所有的值都是按順序儲存的,並且每一個葉子頁到根的距離相同。


B-Tree索引能夠加快訪問資料的速度,因為儲存引擎不再需要進行全表掃描來獲取需要的資料,取而代之的是從索引的根結點開始進行搜尋。根結點的槽中存放了指向子節點的指標,儲存引擎根據這些指標向下層查詢,通過比較節點頁的值和要查詢的值可以找到合適的指標進入下層子節點,這些指標實際上定義了子節點頁中值的上限和下限。最終儲存引擎要麼是找到對應的值們要麼該記錄不存在。

葉子節點比較特別,它們的指標指向的是被索引的資料,而不是其他的節點頁。上圖僅繪製了一個節點和其對應的葉子節點,其實在根結點和葉子節點之間可能有很多層節點頁。樹的深度和表的大小直接相關。

B-Tree對索引是順序組織儲存的,所以很適合查詢範圍資料。例如,在一個基於文字域的索引樹上,按字母順序傳遞連續的值進行查詢是非常合適的。例如:

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)

);

對於表中的每一行資料,索引中包含了last_name、first_name和dob列的值,下圖展示該索引時如何組織資料的儲存的。


可以使用B-Tree索引的查詢型別,B-Tree索引適用於全鍵值、鍵值範圍或鍵字首查詢。其中鍵字首查詢只適用於根據最左字首的查詢。

全值匹配

全值匹配指的是和索引中的所有列進行匹配,例如前面提到的索引可用於查詢姓名為Cuba Allen、出生於1960-01-01的人。

匹配最左字首

前面提到的索引可用於查詢所有姓為Allen的人,即只使用索引的第一列。

匹配列字首

也可以只匹配某一列的值的開頭部分。例如前面提高的索引可用於查詢所有以J開頭的姓的人。這裡也只使用了索引的第一列。

匹配範圍值

例如前面提到的索引可用於查詢姓在Allen和Barrymore之間的人,這裡也只使用了索引的第一列。

精確匹配某一列並範圍匹配另外一列

前面提到的索引也可用於查詢所有姓為Allen,並且名字是字母K開頭(比如Kim、Karl等)的人。即第一列last_name全匹配,第二列first_name範圍匹配。

只訪問索引的查詢

B-Tree通常可以支援“只訪問索引的查詢”,即查詢只需要訪問索引,而無須訪問資料行。

因為索引樹中的節點是有序的,所以除了按值查詢之外,索引還可以用於查詢中的ORDER BY操作(按順序查詢)。一般來說,如果B-Tree可以按照某種方式查詢到值,那麼也可以按照這種方式用於排序。如果ORDER BY子句滿足前面列出的集中查詢型別,則這個索引也可以滿足對應的排序需求。

下面是一些關於B-Tree索引的限制:

a.如果是不會按照索引的最左列開始查詢,則無法使用索引。例如上面例子中的索引無法用於查詢名字為Bill的人,也無法查詢某個特定生日的人,因為這兩列都不是最左資料列。類似地,也無法查詢姓氏以某個字母結尾的人。

b.不能跳過索引的列。也就是說,前面所述的索引無法用於查詢姓為Smith並且在某個特定日期出生的人。如果不指定名(first_name),則MySQL只能使用索引的第一列。

c.如果列中有某個列的範圍查詢,則其右邊所有列都無法使用索引優化查詢。例如有查詢WHERE last_name='Smith' AND first_name LIKE '%J’ AND dob ='1976-12-23',這個查詢只能使用索引的前兩列,因為這裡LIKE是是一個範圍條件(但是伺服器可以把其餘列用於其他目的)。如果範圍查詢列值的數量有限,那麼可以通過使用多個等於條件來代替範圍條件。