聚簇索引
不是一種單獨的索引類型,而是一種數據存儲方式。innodb的聚簇索引實際上在同一個結構中保存了B-tree索引和數據行。
當表有聚簇索引時,數據行實際上是存儲在索引的葉子頁中。
聚簇:表示數據行和相鄰的鍵值緊湊地存儲在一起。一個表只能有一個聚簇索引
聚簇索引如何存放記錄如圖:
聚簇索引的優點:
可以把相關數據保存在一起
數據訪問更快(聚集索引將索引和數據保存在同一個b-tree中)
使用覆蓋索引掃描的查詢可以直接使用頁節點中的主鍵值
聚簇索引的缺點:
聚簇數據提高了IO性能,如果數據全部放在內存中,則訪問的順序就沒那麼重要了
插入速度嚴重依賴插入順序。按主鍵的順序插入是速度最快的。但如果不是按照主鍵順序加載數據,則需在加載完成後最好使用optimize table重新組織一下表
更新聚簇索引列的代價很高。因爲會強制innod將每個被更新的行移動到新的位置
基於聚簇索引的表在插入新行,或主鍵被更新導致需要移動行的時候,可能面臨頁分裂的問題。頁分裂會導致表佔用更多的磁盤空間。
聚簇索引可能導致全表掃描變慢,尤其是行比較稀疏,或由於頁分裂導致數據存儲不連續的時
非聚集索引比想象的更大,因爲二級索引的葉子節點包含了引用行的主鍵列
非聚集索引訪問需要兩次索引查找(非聚集索引中葉子節點保存的行指針指向的是行的主鍵值),對於innodb自適應哈希索引可以減少這樣的重複工作
innodb和myisam的數據分佈對比
myisam的數據分佈按照數據插入順序存儲在磁盤上,如圖:
主鍵分佈,如圖:
col2列索引分佈,如圖:
總結:myisam主鍵索引和其他索引在結構上沒有不同。主鍵索引就是一個名爲primary的非空唯一索引
innodb的數據分佈。存儲數據方式,如圖:
說明:聚簇索引的每個葉子節點都包含了鍵值、事務ID、用於事務和MVCC的回滾指針以及所有的剩餘列。如果主鍵是一個列前綴索引,innodb也會包含完整的主鍵列和剩下的其他列
使用主鍵值當作指針會讓非聚集索引佔用更多的空間,帶來的好處是:innodb在移動時無須更新非聚集索引中的這個‘指針’。
innodb非葉子節點包含了索引列和一個指向下級節點的指針(下一級可以是非葉子節點,也可以是葉子節點)
col2存儲數據方式,如圖:
innodb和myisam保存數據和索引的抽象圖:
在innodb表中按主鍵順序插入行
如果使用innodb表沒有什麼數據需要聚集,可以定義一個代理鍵作爲主鍵,使用auto_increment自增列。這樣可以保證數據行是按順序寫入,對於主鍵做關聯操作的性能也會更好
向聚簇索引插入順序的索引值,如圖:
說明:innodb把每一條記錄都存儲在上一條記錄的後面。當達到頁的最大填充因子(默認是頁大小的15/16,留下部分空間用於修改),下一條記錄會被寫入新的頁中
使用UUID插入聚簇索引的表,如圖:
說明:因爲新行的主鍵值不一定比之前插入的大,索引無法簡單的總是把新行插入到索引的最後,而是需要爲新的行尋找合適的位置——通常是已有數據的中間位置並分配空間。(會增加額外的工作,和數據分佈不夠優化)
缺點:
1.寫入的目標頁可能已經刷到磁盤上並從緩衝中刪除,或還沒被加載到緩存中,innodb在插入之前不得不先找到然後從磁盤中讀取目標頁到內存中。會導致大量的隨機IO
2.因爲寫入是亂序的,innodb不得不頻繁的做頁分裂操作,以便爲新的行分配空間。頁分裂會導致大量移動數據,一次插入需要修改多個頁(最少三頁)而不是一個頁
3.由於頻繁的頁分裂,頁會變得稀疏並不被規則填充,所以數據會有碎片
順序主鍵在什麼時候會有更壞的結果:對於高併發工作負載,在innodb中按主鍵順序插入可能造成明顯的爭用。可能導致間隙鎖競爭和auto_increment鎖機制。
譯者介紹:家華,從事mysqlDBA的工作,記錄自己對mysql的一些總結