主鍵索引就是聚集索引?MySQL 索引類型大梳理

@[toc] 之前松哥在前面的文章中介紹 MySQL 的索引時,有小夥伴表示被概念搞暈了,主鍵索引、非主鍵索引、聚簇索引、非聚簇索引、二級索引、輔助索引等等,今天咱們就來捋一捋這些概念。

1. 按照功能劃分

按照功能來劃分,索引主要有四種:

  • 普通索引
  • 唯一性索引
  • 主鍵索引
  • 全文索引

普通索引就是最最基礎的索引,這種索引沒有任何的約束作用,它存在的主要意義就是提高查詢效率。

普通索引創建方式如下:

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

name 字段就是一個普通索引(括號外面的是索引名,裏邊的是索引的字段)。

唯一性索引則在普通索引的基礎上增加了數據唯一性的約束,一張表中可以同時存在多個唯一性索引,唯一性索引創建方式如下:

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

name 字段就是唯一性索引。

主鍵索引則是在唯一性索引的基礎上又增加了不爲空的約束(換言之,添加了唯一性索引的字段,是可以包含 NULL 值的),即 NOT NULL+UNIQUE,一張表裏最多隻有一個主鍵索引,當然一個主鍵索引中可以包含多個字段。

前面兩個例子中都有主鍵索引的創建方式,我這裏就不再列舉了。

全文索引其實我們很少在 MySQL 中用,如果項目中有做全文索引的需求,一般可以通過 Elasticsearch 或者 Solr 來做,目前比較流行的就是 Elasticsearch 了,松哥之前也錄過專門的視頻,公衆號後臺回覆 es 獲取教程鏈接。

全文索引在 MySQL 中支持的版本也需要大家留意一下:

  • MySQL 5.6 以前的版本,只有 MyISAM 存儲引擎支持全文索引。
  • MySQL 5.6 及以後的版本,MyISAM 和 InnoDB 存儲引擎均支持全文索引。

創建全文索引對字段類型也有要求,只有字段的數據類型爲 CHARVARCHAR 以及 TEXT 等纔可以建立全文索引。

MySQL 的全文索引最開始只支持英文,因爲英文分詞比較方便;中文分詞就比較麻煩,所以最早的 MySQL 全文索引是不支持中文的。從 MySQL5.7.6 版本開始,引入了 ngram 全文分析器來解決分詞問題,並且這個分詞器對 MyISAM 和 InnoDB 引擎都有效。

不過 MySQL 的全文索引並不好用,有這方面的需求還是直接上 Es 吧。

全文索引的創建方式如下:

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

name 字段就是全文索引。

2. 按照物理實現劃分

按照物理實現方式,索引可以分爲兩大類:

  • 聚集索引(有的人也稱之爲“聚簇索引”)
  • 非聚集索引(有的人也稱之爲“非聚簇索引”)

2.1 聚集索引

聚集索引在存儲的時候,可以按照主鍵(不是必須,看情況)來排序存儲數據,B+Tree 的葉子結點就是完整的數據行,查找的時候,找到了主鍵也就找到了完整的數據行。

如下圖,在聚集索引中,葉子結點保存了每一行的數據。

在聚集索引裏,表中數據行按索引的排序方式進行存儲,對查找行很有效。只有當表包含聚集索引時,表內的數據行纔會按找索引列的值在磁盤上進行物理排序和存儲。每張表只能有一個聚集索引,原因很簡單,因爲數據行本身只能按一個順序存儲。

當我們基於 InnoDB 引擎創建一張表的時候,都會創建一個聚集索引,每張表都有唯一的聚集索引:

  1. 如果這張表定義了主鍵索引,那麼這個主鍵索引就作爲聚集索引。
  2. 如果這張表沒有定義主鍵索引,那麼該表的第一個唯一非空索引作爲聚集索引。
  3. 如果這張表也沒有唯一非空索引,那麼 InnoDB 內部會生成一個隱藏的主鍵作爲聚集索引,這個隱藏的主鍵是一個 6 個字節的列,該列的值會隨着數據的插入自增。

基於以上描述大家可以看到,主鍵索引和聚集索引並不是一回事,切勿混淆!

聚集索引最主要的優勢就是查詢快。如果要查詢完整的數據行,使用非聚集索引往往需要回表才能實現,而使用聚集索引則能一步到位。

不過聚集索引也有一些劣勢:

  1. 聚集索引可以減少磁盤 IO 的次數,這在傳統的機械硬盤中是很有優勢的,不過要是固態硬盤或者內存(有時候爲了提高操作效率,數據庫服務器會整一個比較大的內存),這個優勢就不明顯了。
  2. 聚集索引在插入的時候,最好是主鍵自增,自增主鍵插入的時候比較快,直接插入即可,不會涉及到葉子節點分裂等問題(不需要挪動其他記錄);而其他非自增主鍵插入的時候,可能要插入到兩個已有的數據中間,就有可能導致葉子節點分裂等問題,插入效率低(要挪動其他記錄)。如果聚集索引在插入的時候不是自增主鍵,插入效率就會比較低。

2.2 非聚集索引

非聚集索引我們一般也稱爲二級索引或者輔助索引,對於非聚集索引,數據庫會有單獨的存儲空間來存放。非聚集索引在查找的時候要經過兩個步驟,例如執行 select * from user where username='javaboy'(假設 username 字段是非聚集索引),那麼此時需要先搜索 username 這一列索引的 B+Tree,這個 B+Tree 的葉子結點存儲的不是完整的數據行,而是主鍵值,當我們搜索完成後得到主鍵的值,然後拿着主鍵值再去搜索主鍵索引的 B+Tree,就可以獲取到一行完整的數據。

所以如果我們在查詢中用到了非聚集索引,那麼就會搜索兩棵 B+Tree,第一次搜索 B+Tree 拿到主鍵值後再去搜索聚集索引的 B+Tree,這個過程就是所謂的回表。

一張表只能有一個聚集索引,但可以有多個非聚集索引。使用聚集索引的時候,數據的查詢效率高,但如果對數據進行插入,刪除,更新等操作,效率會比非聚集索引低。

3. 小結

總的來說,數據庫索引可以按照兩種思路來分類:按照功能分和按照存儲方式分。

按照功能分,可以分四種:

  • 普通索引
  • 唯一性索引
  • 主鍵索引
  • 全文索引

按照存儲方式分,可以分兩種:

  • 聚集索引
  • 非聚集索引

每種之間有區別又有聯繫,希望上文能爲大家解惑,有問題歡迎留言討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章