1. 程式人生 > >什麼是MySQL 索引?什麼是B+樹?——詳細答案

什麼是MySQL 索引?什麼是B+樹?——詳細答案

MySQL 索引

MySQL索引的建立對於MySQL的高效執行是很重要的,索引可以大大提高MySQL的檢索速度。

索引分單列索引和組合索引:

  • 單列索引,即一個索引只包含單個列,一個表可以有多個單列索引,但這不是組合索引。
  • 組合索引,即一個索引包含多個列。

建立索引時,你需要確保該索引是應用在 SQL 查詢語句的條件(一般作為 WHERE 子句的條件)。

實際上,索引也是一張表,該表儲存了主鍵與索引欄位,並指向實體表的記錄。


索引的缺點:雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對錶進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要儲存資料,還要儲存一下索引檔案。建立索引會佔用磁碟空間的索引檔案。


普通索引

建立索引

這是最基本的索引,它沒有任何限制。它有以下幾種建立方式:

CREATE INDEX indexName ON mytable(username(length)); 

如果是CHAR,VARCHAR型別,length可以小於欄位實際長度;如果是BLOB和TEXT型別,必須指定 length。

修改表結構(新增索引)

ALTER table tableName ADD INDEX indexName(columnName)

建立表的時候直接指定

CREATE TABLE mytable(  
 
ID INT NOT NULL,   
 
username VARCHAR(16) NOT NULL,  
 
INDEX [indexName] (username(length))  
 
); 

刪除索引的語法

DROP INDEX [indexName] ON mytable; 

唯一索引

它與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。它有以下幾種建立方式:

建立索引

CREATE UNIQUE INDEX indexName ON mytable(username(length)) 

修改表結構

ALTER table mytable ADD UNIQUE [indexName] (username(length))

建立表的時候直接指定

CREATE TABLE mytable(  
 
ID INT NOT NULL,   
 
username VARCHAR(16) NOT NULL,  
 
UNIQUE [indexName] (username(length))  
 
); 

使用ALTER 命令新增和刪除索引

有四種方式來新增資料表的索引:

ALTER TABLE tbl_name ADD PRIMARY KEY (column_list)

: 該語句新增一個主鍵,這意味著索引值必須是唯一的,且不能為NULL。

ALTER TABLE tbl_name ADD UNIQUE index_name (column_list)

: 這條語句建立索引的值必須是唯一的(除了NULL外,NULL可能會出現多次)。

ALTER TABLE tbl_name ADD INDEX index_name (column_list)

: 新增普通索引,索引值可出現多次。

ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list)

:該語句指定了索引為 FULLTEXT ,用於全文索引。

以下例項為在表中新增索引。

ALTER TABLE testalter_tbl ADD INDEX (c);

你還可以在 ALTER 命令中使用 DROP 子句來刪除索引。嘗試以下例項刪除索引:

ALTER TABLE testalter_tbl DROP INDEX c;

使用 ALTER 命令新增和刪除主鍵

主鍵只能作用於一個列上,新增主鍵索引時,你需要確保該主鍵預設不為空(NOT NULL)。例項如下:

ALTER TABLE testalter_tbl MODIFY i INT NOT NULL;
ALTER TABLE testalter_tbl ADD PRIMARY KEY (i)

你也可以使用 ALTER 命令刪除主鍵:

ALTER TABLE testalter_tbl DROP PRIMARY KEY;

刪除主鍵時只需指定PRIMARY KEY,但在刪除索引時,你必須知道索引名。


顯示索引資訊

你可以使用 SHOW INDEX 命令來列出表中的相關的索引資訊。可以通過新增 \G 來格式化輸出資訊。

嘗試以下例項:

SHOW INDEX FROM table_name; \G

B+Tree

B+ 樹是一種樹資料結構,是一個n叉排序樹,每個節點通常有多個孩子,一棵B+樹包含根節點、內部節點和葉子節點。根節點可能是一個葉子節點,也可能是一個包含兩個或兩個以上孩子節點的節點。

B+ 樹通常用於資料庫和作業系統的檔案系統中。NTFS, ReiserFS, NSS, XFS, JFS, ReFS 和BFS等檔案系統都在使用B+樹作為元資料索引。B+ 樹的特點是能夠保持資料穩定有序,其插入與修改擁有較穩定的對數時間複雜度。B+ 樹元素自底向上插入。

B+樹是應檔案系統所需而出的一種B樹的變型樹。

1.有n棵子樹的結點中含有n個關鍵字,每個關鍵字不儲存資料,只用來索引,所有資料都儲存在葉子節點。

2.所有的葉子結點中包含了全部關鍵字的資訊,及指向含這些關鍵字記錄的指標,且葉子結點本身依關鍵字的大小自小而大順序連結。

3.所有的非終端結點可以看成是索引部分,結點中僅含其子樹(根結點)中的最大(或最小)關鍵字。

通常在B+樹上有兩個頭指標,一個指向根結點,一個指向關鍵字最小的葉子結點。


查詢

對B+樹可以進行兩種查詢運算:

  1. 從最小關鍵字起順序查詢;
  2. 從根結點開始,進行隨機查詢。

在查詢時,若非終端結點上的關鍵值等於給定值,並不終止,而是繼續向下直到葉子結點。因此,在B+樹中,不管查詢成功與否,每次查詢都是走了一條從根到葉子結點的路徑。其餘同B-樹的查詢類似。

以下是從根節點查詢葉子節點k的虛擬碼:

Function: search (k)  
    return tree_search (k, root); Function: tree_search (k, node)  
    if node is a leaf then        return node;  
    switch k do    case k < k_0    
        return tree_search(k, p_0);  
    case k_i ≤ k < k_{i+1}    
        return tree_search(k, p_{i+1});  
    case k_d ≤ k    
        return tree_search(k, p_{d+1});

插入

m階B樹的插入操作在葉子結點上進行,假設要插入關鍵值a,找到葉子結點後插入a,做如下演算法判別:

  • ①如果當前結點是根結點並且插入後結點關鍵字數目小於等於m,則演算法結束;
  • ②如果當前結點是非根結點並且插入後結點關鍵字數目小於等於m,則判斷若a是新索引值時轉步驟④後結束,若a不是新索引值則直接結束;
  • ③如果插入後關鍵字數目大於m(階數),則結點先分裂成兩個結點X和Y,並且他們各自所含的關鍵字個數分別為:u=大於(m+1)/2的最小整數,v=小於(m+1)/2的最大整數;

由於索引值位於結點的最左端或者最右端,不妨假設索引值位於結點最右端,有如下操作:

如果當前分裂成的X和Y結點原來所屬的結點是根結點,則從X和Y中取出索引的關鍵字,將這兩個關鍵字組成新的根結點,並且這個根結點指向X和Y,演算法結束;

如果當前分裂成的X和Y結點原來所屬的結點是非根結點,依據假設條件判斷,如果a成為Y的新索引值,則轉步驟④得到Y的雙親結點P,如果a不是Y結點的新索引值,則求出X和Y結點的雙親結點P;然後提取X結點中的新索引值a’,在P中插入關鍵字a’,從P開始,繼續進行插入演算法;

④提取結點原來的索引值b,自頂向下,先判斷根是否含有b,是則需要先將b替換為a,然後從根結點開始,記錄結點地址P,判斷P的孩子是否含有索引值b而不含有索引值a,是則先將孩子結點中的b替換為a,然後將P的孩子的地址賦值給P,繼續搜尋,直到發現P的孩子中已經含有a值時,停止搜尋,返回地址P。


刪除

B+樹的刪除也僅在葉子結點進行,當葉子結點中的最大關鍵字被刪除時,其在非終端結點中的值可以作為一個“分界關鍵字”存在。若因刪除而使結點中關鍵字的個數少於m/2 (m/2結果取上界,如5/2結果為3)時,其和兄弟結點的合併過程亦和B-樹類似。


為什麼說B+樹比B 樹更適合實際應用中作業系統的檔案索引和資料庫索引? 

一、B+樹的磁碟讀寫代價更低

  • B+樹的內部結點並沒有指向關鍵字具體資訊的指標。因此其內部結點相對B樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入記憶體中的需要查詢的關鍵字也就越多。相對來說IO讀寫次數也就降低了。舉個例子:假設磁碟中的一個盤塊容納16bytes,而一個關鍵字2bytes,一個關鍵字具體資訊指標2bytes。一棵9階B樹(一個結點最多8個關鍵字)的內部結點需要2個盤塊。而B+樹內部結點只需要1個盤塊。當需要把內部結點讀入記憶體中的時候,B樹就比B+樹多一次盤塊查詢時間(在磁碟中就是碟片旋轉的時間)。

二、B+樹的查詢效率更加穩定

  • 由於非終結點並不是最終指向檔案內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查詢必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。