經常聽到程序員調侃面試時被要求手撕B樹、紅黑樹,但是入職後卻只能做一個安靜的CRUD boy。

B樹與紅黑樹最廣泛的應用就是資料庫索引,熟練使用索引是程序員最重要的基本功之一。索引的數據結構可以是樹,也可以是哈希表。常用的資料庫都是樹結構的索引,本篇的背景也全部以樹結構的索引為前提。本文旨在梳理各種常見的索引類型,簡明扼要地說明它們的區別與聯繫,不討論數據結構與演算法。話不多說,直接上乾貨。

索引

資料庫只做兩件事情:存儲數據、檢索數據。而索引是在你存儲的數據之外,額外保存一些路標(一般是B+樹),以減少檢索數據的時間。所以索引是主數據衍生的附加結構。

一張表可以建立任意多個索引,每個索引可以是任意多個欄位的組合。索引可能會提高查詢速度(如果查詢時使用了索引),但一定會減慢寫入速度,因為每次寫入時都需要更新索引,所以索引只應該加在經常需要搜索的列上,不要加在寫多讀少的列上。

單列索引 與 複合索引

只包含一個欄位的索引叫做單列索引,包含兩個或以上欄位的索引叫做複合索引(或組合索引)。建立複合索引時,欄位的順序極其重要。

下面這個SQL語句在 列X,列Y,列Z 上建立了一個複合索引。

CREATE INDEX 索引名 ON 表名(列名X, 列名Y, 列名Z);

其實這相當於建立了三個索引,分別是:

1、單列索引(列X) 2、複合索引(列X, 列Y) 3、複合索引(列X,列Y,列Z)。

如何理解呢?

我們可以把多個欄位組合的索引比喻成一個老式的紙質電話簿,三列分別是:

姓 - 名 - 電話號碼

電話簿中的內容先按照姓氏的拼音排序,相同姓氏再按名字的拼音排序,這相當於在(姓,名)上建立了一個複合索引。你可以通過這個索引快速找到所有具有特定姓氏的人的電話號碼,也可以快速找到具有特定 姓-名 組合的人的電話號碼。然而,想像一下,如果你想找到某個特定名字的人,其實這個索引是沒有用的,你只能從頭到尾遍歷整個電話簿。

唯一索引 與 主鍵

唯一索引是在表上一個或者多個欄位組合建立的索引,這個(或這幾個)欄位的值組合起來在表中不可以重複。一張表可以建立任意多個唯一索引,但一般只建立一個。

主鍵是一種特殊的唯一索引,區別在於,唯一索引列允許null值,而主鍵列不允許為null值。一張表最多建立一個主鍵,也可以不建立主鍵。

聚簇索引、非聚簇索引、主鍵

在《資料庫原理》一書中是這麼解釋聚簇索引和非聚簇索引的區別的:

聚簇索引的葉子節點就是數據節點,而非聚簇索引的葉子節點仍然是索引節點,只不過有指向對應數據塊的指針。

怎麼理解呢?

聚簇索引的順序,就是數據在硬碟上的物理順序。一般情況下主鍵就是默認的聚簇索引。

一張表只允許存在一個聚簇索引,因為真實數據的物理順序只能有一種。如果一張表上還沒有聚簇索引,為它新創建聚簇索引時,就需要對已有數據重新進行排序,所以對錶進行修改速度較慢是聚簇索引的缺點,對於經常更新的列不宜建立聚簇索引

聚簇索引性能最好,因為一旦具有第一個索引值的記錄被找到,具有連續索引值的記錄也一定物理地緊跟其後。一張表只能有一個聚簇索引,所以非常珍貴,必須慎重設置,一般要根據這個表最常用的SQL查詢方式選擇某個(或多個)欄位作為聚簇索引(或複合聚簇索引)。

聚簇索引默認是主鍵,如果表中沒有定義主鍵,InnoDB[1]會選擇一個唯一的非空索引代替(「唯一的非空索引」是指列不能出現null值的唯一索引,跟主鍵性質一樣)。如果沒有這樣的索引,InnoDB會隱式地定義一個主鍵來作為聚簇索引。

聚簇索引 與 唯一索引

嚴格來說,聚簇索引不一定是唯一索引,聚簇索引的索引值並不要求是唯一的,唯一聚簇索引才是!在一個有聚簇索引的列上是可以插入兩個或多個相同值的,這些相同值在硬碟上的物理排序與聚簇索引的排序相同,僅此而已。

原圖已被建議修改,謝謝大家的支持。我將加強思想道德建設,並致力於寫出更多的乾貨分享給大家。

參考

  1. ^MySQL的資料庫引擎之一,為MySQL AB發布binary的標準之一。

推薦閱讀:

相关文章