《高性能Mysql》講聚簇索引


《高性能Mysql》原文

 

聚簇索引如下圖為聚簇所有的存儲方式,聚簇實際不是一種索引,而是一種數據的存儲方式,InnoDB的聚簇事假在同一個結構中保存了B-Tree索引和數據行。

   當表有聚簇索引時,他的數據行實際存在放葉子頁InnoDb通過主鍵聚集數據,如果沒有定義主鍵則InnoDB會選擇一個唯一的非空索引代替。

 1.聚簇索引的特性

1.1當表存在主鍵時,Innodb 使用 主鍵作為聚簇索引

1.2當表沒有主鍵時,Innodb 使用第一個唯一約束索引(這個唯一索引必須是不包含null列的)作為聚簇索引

1.3當表沒有主鍵,也沒有合適的唯一索引時,Innodb隱含創建一個包含rowid 的聚簇索引

 

 下面展示了聚族索引中的記錄是如何存放的。注意到,葉子頁包含了行的全部數據,但是節點頁只包含了索引列。

2.    聚族索引的優點

  • 可以把相關數據保存在一起。例如實現電子郵件時,可以根據用戶ID來聚集數據,這樣只需要從磁盤讀取少數的數據頁就能獲取某個用戶的全部郵件。如果沒有使用聚族索引,則每封郵件都可能導致一次磁盤I/O;
  • 數據訪問更快。聚族索引將索引和數據保存在同一個B-Tree中,因此從聚族索引中獲取數據通常比在非聚族索引中查找更快。
  • 使用覆蓋索引掃描的查詢可以直接使用節點中的主鍵值。

聚族索引的缺點

  • 聚簇數據最大限度的提高了I/O密集型應用的性能,但如果數據全部都放在內存中,則訪問的順序就沒有那么重要了,聚簇索引也就沒有那么優勢了;
  • 插入速度嚴重依賴於插入順序。按照主鍵的順序插入是加載數據到InnoDB表中速度最快的方式。但如果不是按照主鍵順序加載數據,那么在加載完成后最好使用OPTIMIZE TABLE命令重新組織一下表。
  • 更新聚簇索引列的代價很高,因為會強制InnoDB將每個被更新的行移動到新的位置。
  • 基於聚簇索引的表在插入新行,或者主鍵被更新導致需要移動行的時候,可能面臨“頁分裂”的問題。當行的主鍵值要求必須將這一行插入到某個已滿的頁中時,存儲引擎會將該頁分裂成兩個頁面來容納該行,這就是一次分裂操作。頁分裂會導致表占用更多的磁盤空間。
  • 聚簇索引可能導致全表掃描變慢,尤其是行比較稀疏,或者由於頁分裂導致數據存儲不連續的時候。
  • 二級索引(非聚簇索引)可能比想象的要更大,因為在二級索引的葉子節點包含了引用行的主鍵列。
  • 二級索引訪問需要兩次索引查找,而不是一次。

 

  1. InnoDBMyISAM的數據分布對比

    聚簇索引和非聚簇索引的數據分布有區別,以及對應的主鍵索引和二級索引的數據分布也有區別。

4.1MyISAM的主鍵索引和二級索引

    MyISAM的數據分布非常簡單,MyISAM按照數據插入的順序存儲在磁盤上。在行的旁邊顯示了行號,從0開始遞增。因為行是定長的,所以MyISAM可以從表的開頭跳過所需的字節找到需要的行。這種分布方式很容易創建索引。並且,MyISAM中主鍵索引和其他索引在結構上沒有什么不同。主鍵索引就是一個名為primary的唯一非空索引。如下圖:

1、MyISAM數據行分布

2、MyISAM的主鍵分布

3、MyISAM上的其他索引分布(二級索引)

4.2InnoDB的主鍵索引和二級索引

    InnoDB的數據分布,因為InnoDB支持聚簇索引,索引使用非常不同的方式存儲這樣的數據,如下圖:

    仔細查看,會注意到該圖顯示了整個表,而不是只有索引。因為在InnoDB中,聚簇索引“就是”表,所以不像MyISAM那樣需要獨立的行存儲。聚簇索引的每個葉子節點都包含了主鍵值、事務ID、用於事務和MVCC的回滾指針以及所有的剩余列。如果主鍵是一個列前綴索引,InnoDB也會包含完整的主鍵列和剩下的其他列。

    還有一點和MyISAM的不同是,InnoDB的二級索引和聚簇索引很不相同。InnoDB二級索引的葉子節點中存儲的不是“行指針”,而是主鍵值,並以此作為指向行的“指針”。這樣的策略減少了當出現行移動或者數據頁分裂時二級索引的維護工作。使用主鍵值當作指針會讓二級索引占用更多的空間,換來的好處是,InnoDB在移動行時無需更新二級索引中的這個“指針”。下圖就是InnoDB的二級索引:

4.3MyISAMInnoDB的對比

5、在InnoDB表中按主鍵順序插入行

    如果正在使用InnoDB表並且沒有什么數據需要聚集,那么可以定義一個代理鍵作為主鍵,這種主鍵的數據應該和應用無關,最簡單的方法是使用auto_increment自增列。這樣可以保證數據行是按照順序寫入,對於根據主鍵做關聯操作的性能也會更好。

    最好避免隨機的聚簇索引,特別對於I/O密集型的應用。例如,從性能的角度考慮,使用UUID作為聚簇索引會很糟糕:它使得聚簇索引的插入變得完全隨機,這是最壞的情況,使得數據沒有任何聚集特性。通過測試,向UUID主鍵插入行不僅花費的時間更長,而且索引占用的空間也更大。這一方面是由於主鍵字段更長,另一方面毫無疑問是由於頁分裂和碎片導致的。

    這是由於當主鍵的值是順序的,則InnoDB把每一條記錄都存儲在上一條記錄的后面。當達到頁的最大填充因子時(InnoDB默認的最大填充因子是頁大小的15/16,留出的部分空間用於以后修改),下一條記錄就會寫入新的頁中。一旦數據按照這樣順序的方式加載,主鍵頁就會近似於被順序的記錄填滿,這也是所期望的結果。

    而當采用UUID的聚簇索引的表插入數據,因為新行的主鍵值不一定比之前的插入值大,所以InnoDB無法簡單的總是把新行插入到索引的最后,而是需要為新的行尋找合適的位置----通常是已有數據的中間位置----並且分配空間。這會增加很多額外的工作,並導致數據分布不夠優化。下面是總結的一些缺點:

  • 寫入目標頁可能已經刷到磁盤上並從緩存中移除,或者是還沒有被加載到緩存中,InnoDB在插入之前不得不先找到並從磁盤讀取目標頁到內存中,這將導致大量的隨機I/O;
  • 因為寫入是亂序的,InnoDB不得不頻繁的做頁分裂操作,以便為新的行分配空間。頁分裂會導致移動大量數據,一次插入最少需要修改三個頁而不是一個頁。
  • 由於頻繁的頁分裂,頁會變得稀疏並被不規則的填充,所以最終數據會有碎片。
  • 把這些隨機值載入到聚簇索引以后,需要做一次optimize table來重建表並優化頁的填充。

注意:順序主鍵也有缺點:對於高並發工作負載,在InnoDB中按主鍵順序插入可能會造成明顯的爭用。主鍵的上界會成為“熱點”。因為所有的插入都發生在這里,所以並發插入可能導致間隙鎖競爭。另一個熱點可能是auto_increment鎖機制;如果遇到這個問題,則可能需要考慮重新設計表或者應用,或者更改innodb_autonc_lock_mode配置。

6.其他說明

1.覆蓋索引

 一個索引包含(或者說覆蓋)所有需要查詢的字段,我們成為覆蓋索引。

 

2.使用索引掃描來排序

Mysql有兩種方式可以生成有序的結果:通過排序操作;或者按照索引順序掃描。如果Explain出來的type列值為“index”則說明mysql使用索引掃描來做排序。

只有當索引的順序和Order By子句的順序完全一致,並且所有列的排序方向(倒序或者正序)都一樣時,Msyql才能使用索引對結果進行排序。

 

3. 維護索引和表

1.如果碰到古怪的問題,或者莫須有的主鍵沖突,可以運行 check table來查看表是否有損壞,如果有損壞可以通過repair table 來修復表,也可以通過一個不做任何操作的alter命令來重建表,例如修改表的引擎為當前引擎。

 

 

 

 

https://blog.csdn.net/liuguanghaoputin/article/details/44595877


免責聲明!

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



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