Mysql聚簇索引和非聚簇索引


Mysql聚簇索引和非聚簇索引

最近看了《高性能Mysql》那本書,總結下聚簇索引。

聚簇索引並不是一種單獨的索引類型,而是一種數據存儲方式,具體的細節依賴於實現方式,InnoDB的聚簇索引實際上在同一個結構中保存了B+Tree索引和數據行。

當表中有聚簇索引時,它的數據實際上存儲在索引的葉子頁中(葉子頁中包含了行的全部數據)。而沒有聚簇索引時B+Tree葉子頁存放的是指向數據的指針。(頁是mysql存儲引擎最小的存儲單元,InnoDB每個頁默認大小為16k)可以理解為 有聚簇索引時,數據和對應的葉子頁在同一頁中,沒有聚簇索引時,葉子頁和對應的數據不在同一頁中。

 

InnoDB存儲引擎通過主鍵聚集數據(聚簇索引),如果沒有定義主鍵,InnoDB會選擇一個唯一的非空索引代替。如果沒有唯一索引,InnoDB會隱式定義一個主鍵來作為聚簇索引。InnoDB 只聚集在同一個頁面中的記錄。包含相鄰健值的頁面可能相距甚遠。

MyISAM中主鍵索引和其他索引 都指向物理行 (非聚簇索引)

下圖展示了聚簇索引是如何存放的(圖片來自《高性能MySQL(第三版)》):

 

 

聚簇索引和非舉措索引的區別:

聚簇索引,索引的順序就是數據存放的順序(物理順序),只要索引是相鄰的,那么對應的數據一定也是相鄰地存放在磁盤上的。一張數據表只能有一個聚簇索引。(一個數據頁中數據物理存儲是有序的)

非聚簇索引通過葉子節點指針找到數據頁中的數據,所以非聚簇索引是邏輯順序。

聚集索引的優點:

1.數據存放的順序和索引順序一致,可以把相關數據保存在一起。例如實現電子郵箱時,可以根據用戶 ID 來聚集數據,這樣只需要從磁盤讀取少數的數據頁就能獲取某個用戶的全部郵件。如果沒有使用聚簇索引,則每封郵件都可能導致一次磁盤 I/O。

2.數據訪問更快,聚簇索引將索引和數據保存在同一個B-Tree中,因此從舉措索引中獲取數據通常比非聚簇索引查找更快。

3.使用覆蓋索引掃描的查詢可以直接使用頁節點中的主鍵值(二級索引(非聚簇索引) 的葉子節點保存的不是指向行的物理位置的指針,而是行的主鍵值)

(PS:覆蓋索引:Mysql 可以使用索引來直接獲取列的數據,這樣就不需要查到索引后,然后通過葉子節點的指針回表讀取數據行,如果索引的葉子節點中已經包含了或者說覆蓋 所有需要查詢的字段的值,那么就沒有必要再回表查詢了,這種稱之為“覆蓋索引”)

聚簇索引的缺點:

    1.聚簇數據提高了IO性能,如果數據全部放在內存中,則訪問的順序就沒那么重要了

   2. 插入速度嚴重依賴插入順序。按主鍵的順序插入是速度最快的。但如果不是按照主鍵順序加載數據,則需在加載完成后最好使用optimize table重新組織一下表

    3.更新聚簇索引列的代價很高。因為會強制innod將每個被更新的行移動到新的位置

    4.基於聚簇索引的表在插入新行,或主鍵被更新導致需要移動行的時候,可能面臨頁分裂的問題。頁分裂會導致表占用更多的磁盤空間。

    5.聚簇索引可能導致全表掃描變慢,尤其是行比較稀疏,或由於頁分裂導致數據存儲不連續的時

    6.非聚集索引比想象的更大,因為二級索引的葉子節點包含了引用行的主鍵列

    7.非聚集索引訪問需要兩次索引查找(非聚集索引中葉子節點保存的行指針指向的是行的主鍵值),對於innodb自適應哈希索引可以減少這樣的重復工作

聚簇索引盡量選擇有序的列(如AUTO_INCREMENT自增列),這樣可以保證數據行是順序寫入,對於根據主鍵做關聯操作的性能也會更好。

最好避免隨機的(不連續且值的分布范圍非常大)聚簇索引,特別是對於I/O密集型的應用。

從性能角度考慮,使用UUID來做聚簇索引會很糟糕,它使得聚簇索引的插入變得完全隨機,這是最壞的情況,是的數據沒有任何聚集的特性。

總結下使用類似UUID這種隨機的聚簇索引的缺點:

1.UUID字段長,索引占用的空間更大。

2.寫入是亂序的,InnoDB不得不頻繁的做頁分裂操作,以便新的行分配空間,頁分裂會導致移動大量數據,一次插入最少需要修改三個頁而不是一個頁。

3.寫入的目標頁可能已經刷到磁盤上並從緩存中移除,或者還沒有被加載到緩存中,InnoDB在插入之前不得不先找到並從磁盤讀取目標頁到內存中,這將導致大量的隨機IO。

4.頻繁的頁分裂,頁會變的稀疏並被不規則的填充,會產生空間碎片。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM