聚集索引與非聚集索引

摘抄和整理,非原創!!!

官方定義:

  1. 在《數據庫原理》一書中是這麼解釋聚簇索引和非聚簇索引的區別的:  
  2. 聚簇索引的葉子節點就是數據節點,  
  3. 而非聚簇索引的葉子節點仍然是索引節點,只不過有指向對應數據塊的指針。  

 

聚集索引:表數據按照索引的順序來存儲的,也就是說索引項的順序與表中記錄的物理順序一致。對於聚集索引,葉子結點即存儲了真實的數據行,不再有另外單獨的數據頁。 在一張表上最多隻能創建一個聚集索引,因爲真實數據的物理順序只能有一種。

"聚集"指實際的數據行和相關的鍵值都保存在一起

聚簇索引的二級索引:葉子節點不會保存引用的行的物理位置,而是保存了行的主鍵值

 

注意:數據的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那麼對應的數據一定也是相鄰地存放在磁盤上的,如果主鍵不是自增id,那麼可以想象,它會幹些什麼,不斷地調整數據的物理地址、分頁,當然也有其他一些措施來減少這些操作,但卻無法徹底避免。但,如果是自增的,那就簡單了,它只需要一頁一頁地寫,索引結構相對緊湊,磁盤碎片少,效率也高。

 

非聚集索引:表數據存儲順序與索引順序無關。對於非聚集索引,葉結點包含索引字段值及指向數據頁數據行的邏輯指針,其行數量與數據錶行數據量一致

MyISAM的B+Tree的葉子節點上的data,並不是數據本身,而是數據存放的地址主索引和輔助索引沒啥區別,只是主索引中的key一定得是唯一的

 

聚簇索引是對磁盤上實際數據重新組織以按指定的一個或多個列的值排序的算法。特點是存儲數據的順序和索引順序一致。一般情況下主鍵會默認創建聚簇索引,且一張表只允許存在一個聚簇索引。

 

因此,MYSQL中不同的數據存儲引擎對聚簇索引的支持不同就很好解釋了。下面,我們可以看一下MYSQL中MYISAM和INNODB兩種引擎的索引結構。

如原始數據爲:




 

MyISAM引擎的數據存儲方式如圖:



 

MYISAM是按列值與行號來組織索引的。它的葉子節點中保存的實際上是指向存放數據的物理塊的指針。從MYISAM存儲的物理文件我們能看出,MYISAM引擎的索引文件(.MYI)和數據文件(.MYD)是相互獨立的。

而InnoDB按聚簇索引的形式存儲數據,所以它的數據佈局有着很大的不同。它存儲數據的結構大致如下:



 

注:聚簇索引中的每個葉子節點包含主鍵值、事務ID、回滾指針(rollback pointer用於事務和MVCC)和餘下的列(如col2)。

INNODB的二級索引與主鍵索引有很大的不同。InnoDB的二級索引的葉子包含主鍵值,而不是行指針(row pointers),這減小了移動數據或者數據頁面分裂時維護二級索引的開銷,因爲InnoDB不需要更新索引的行指針。其結構大致如下:



 

INNODB和MYISAM的主鍵索引與二級索引的對比:



 

InnoDB的的二級索引的葉子節點存放的是KEY字段加主鍵值。因此,通過二級索引查詢首先查到是主鍵值,然後InnoDB再根據查到的主鍵值通過主鍵索引找到相應的數據塊。而MyISAM的二級索引葉子節點存放的還是列值與行號的組合,葉子節點中保存的是數據的物理地址。所以可以看出MYISAM的主鍵索引和二級索引沒有任何區別,主鍵索引僅僅只是一個叫做PRIMARY的唯一、非空的索引,且MYISAM引擎中可以不設主鍵。

 

 爲了更形象說明這兩種索引的區別,我們假想一個表如下圖存儲了4行數據。其中Id作爲主索引,Name作爲輔助索引。圖示清晰的顯示了聚簇索引和非聚簇索引的差異。

 

 

 

對於聚簇索引存儲來說,行數據和主鍵B+樹存儲在一起,輔助鍵B+樹只存儲輔助鍵和主鍵,主鍵和非主鍵B+樹幾乎是兩種類型的樹。對於非聚簇索引存儲來說,主鍵B+樹在葉子節點存儲指向真正數據行的指針,而非主鍵。

InnoDB使用的是聚簇索引,將主鍵組織到一棵B+樹中,而行數據就儲存在葉子節點上,若使用"where id = 14"這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對應的葉節點,之後獲得行數據。若對Name列進行條件搜索,則需要兩個步驟:第一步在輔助索引B+樹中檢索Name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引B+樹種再執行一次B+樹檢索操作,最終到達葉子節點即可獲取整行數據。

MyISM使用的是非聚簇索引,非聚簇索引的兩棵B+樹看上去沒什麼不同,節點的結構完全一致只是存儲的內容不同而已,主鍵索引B+樹的節點存儲了主鍵,輔助鍵索引B+樹存儲了輔助鍵。表數據存儲在獨立的地方,這兩顆B+樹的葉子節點都使用一個地址指向真正的表數據,對於表數據來說,這兩個鍵沒有任何差別。由於索引樹是獨立的,通過輔助鍵檢索無需訪問主鍵的索引樹。

爲了更形象說明這兩種索引的區別,我們假想一個表如下圖存儲了4行數據。其中Id作爲主索引,Name作爲輔助索引。圖示清晰的顯示了聚簇索引和非聚簇索引的差異。

 



 

我們重點關注聚簇索引,看上去聚簇索引的效率明顯要低於非聚簇索引,因爲每次使用輔助索引檢索都要經過兩次B+樹查找,這不是多此一舉嗎?聚簇索引的優勢在哪?

1 由於行數據和葉子節點存儲在一起,這樣主鍵和行數據是一起被載入內存的,找到葉子節點就可以立刻將行數據返回了,如果按照主鍵Id來組織數據,獲得數據更快。

2 輔助索引使用主鍵作爲"指針" 而不是使用地址值作爲指針的好處是,減少了當出現行移動或者數據頁分裂時輔助索引的維護工作,使用主鍵值當作指針會讓輔助索引佔用更多的空間,換來的好處是InnoDB在移動行時無須更新輔助索引中的這個"指針"。也就是說行的位置(實現中通過16K的Page來定位,後面會涉及)會隨着數據庫裏數據的修改而發生變化(前面的B+樹節點分裂以及Page的分裂),使用聚簇索引就可以保證不管這個主鍵B+樹的節點如何變化,輔助索引樹都不受影響。

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