聚簇索引
數據庫表的索引從數據存儲方式上可以分為聚簇索引和非聚簇索引(又叫二級索引)兩種。Innodb的聚簇索引在同一個B-Tree中保存了索引列和具體的數據,在聚簇索引中,實際的數據保存在葉子頁中,中間的節點頁保存指向下一層頁面的指針。“聚簇”的意思是數據行被按照一定順序一個個緊密地排列在一起存儲。一個表只能有一個聚簇索引,因為在一個表中數據的存放方式只有一種。
一般來說,將通過主鍵作為聚簇索引的索引列,也就是通過主鍵聚集數據。下圖展示了Innodb中聚簇索引的結構(圖片來自《高性能MySQL(第三版)》):
聚簇索引的結構
這里要特別注意頁
的概念,一個頁可以理解為一塊具有一定大小的連續的存儲區域。相同頁內的數據行在物理上是相鄰的,因此邏輯上鍵值相鄰的頁在物理上可能相隔很遠。
在中間的某個節點頁中,主鍵<11的葉子頁和11<主鍵<21的葉子頁分別被兩個指針所指向,且主鍵<11的葉子頁也有一個指針指向了11<主鍵<21的葉子頁,其余頁之間的關系也是一樣。
聚簇索引的優點
- 聚簇索引將索引和數據行保存在同一個B-Tree中,查詢通過聚簇索引可以直接獲取數據,相比非聚簇索引需要第二次查詢(非覆蓋索引的情況下)效率要高。
- 聚簇索引對於范圍查詢的效率很高,因為其數據是按照大小排列的,
聚簇索引的缺點
- 聚簇索引的更新代價比較高,如果更新了行的聚簇索引列,就需要將數據移動到相應的位置。這可能因為要插入的頁已滿而導致“頁分裂”。
- 插入速度嚴重依賴於插入順序,按照主鍵進行插入的速度是加載數據到Innodb中的最快方式。如果不是按照主鍵插入,最好在加載完成后使用
OPTIMIZE TABLE
命令重新組織一下表。 - 聚簇索引在插入新行和更新主鍵時,可能導致“頁分裂”問題。
- 聚簇索引可能導致全表掃描速度變慢,因為可能需要加載物理上相隔較遠的頁到內存中(需要耗時的磁盤尋道操作)。
非聚簇索引
非聚簇索引,又叫二級索引。二級索引的葉子節點中保存的不是指向行的物理指針,而是行的主鍵值。當通過二級索引查找行,存儲引擎需要在二級索引中找到相應的葉子節點,獲得行的主鍵值,然后使用主鍵去聚簇索引中查找數據行,這需要兩次B-Tree查找。
總結
下面是Innodb聚簇索引和非聚簇索引的示意圖(圖片來自《高性能MySQL(第三版)》:
Innodb聚簇索引和非聚簇索引