天天看點

【資料庫】淺析Innodb的聚集索引與非聚集索引

Mysql存儲引擎之一的Innodb的索引,可以分為聚集索引與非聚集索引,這兩種索引都是使用B+樹組織的。

本文不講解什麼是索引,對索引不了解的同學可以先移步到我的另外一篇文章【資料庫】mysql索引簡談

在分析這兩種索引之前,我們先建立一個Person表:

CREATE TABLE person  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
  `name` varchar(255) COMMENT '姓名',
  `age` int(11) COMMENT '年齡',
  PRIMARY KEY (`id`),
  KEY(`name`)
) ENGINE = InnoDB;
           

其中id為主鍵,name為普通索引。

這是其中的部分資料:

【資料庫】淺析Innodb的聚集索引與非聚集索引

假設我現在需要查找id=5的記錄,按照正常邏輯,需要去周遊該表中所有的資料。在最壞的情況下,需要周遊5次才能取到資料,時間複雜度為O(N)。正常的表中會有幾萬、幾十萬條資料,使用這種周遊的方法的話,那業務别做了,公司别開了,倒閉算了。

使用索引後,會将表中的記錄按照某種規則轉換為平衡樹結構,大大減少查詢的次數,具體是什麼結構,取決于建立的索引的類型。

聚集索引:

聚集索引,也成聚簇索引,一般情況下,指定id為主鍵,就會生成一個以id為基礎的聚集索引。

在聚集索引的樹結構中,所有節點都會存儲主鍵值,而葉子節點還會多存儲主鍵對應的行記錄。

此外,真實的資料行會按照主鍵排序,順序存儲在磁盤上,比如id為1和2的對應記錄在磁盤上相鄰存儲。

一張表隻有一個主鍵,是以一個表隻有一個聚集索引。

非聚集索引:

非聚集索引,也是一顆平衡樹。所有節點都會存儲索引列的值,比如這裡就是name列的值,葉子節點還會多存儲該name值所對應的的聚集索引的值,即主鍵的值。

不同于聚集索引,真實的資料行不會按照非聚集索引排序存儲,但索引項的内容是按順序存儲的。

一個表可以有多個非主鍵索引,是以會建立多個非聚集索引,每建立一個非聚集索引,都會将該非聚集索引關聯的字段資料複制出來一份,用于生成以該列為基礎的平衡樹。這樣的操作會增加表的體積,占用磁盤空間,是以不是索引越多越好。

通過非聚集索引查詢資料時,查詢到葉子節點上的主鍵值後,再利用這個主鍵值查詢聚集索引,進而查詢到具體的行記錄,這個需要周遊兩次樹。

是以,不管以任何方式查詢資料,最後都會利用聚集索引查詢資料,在我們之前定義的表中,聚集索引是通往真實記錄的唯一大道。

但所謂條條大路通羅馬,我們稍微改變表的結構就可以,隻需要建立一個組合索引,包括name和age字段。

那麼,當我們執行這條語句時:

select age from person where name='cc';
           

由于建立的是組合索引,是以每個葉子節點存儲的是name和age兩個字段的值,以及主鍵id的值。由于此時已經有age值,直接傳回即可,此時不需要再通過這個主鍵id查詢聚集索引。