聚簇索引詳解(轉)

聚簇索引不是一個獨立的索引類型,而是一種數據存儲的方式。

InnoDB使用B-Tree來實現聚簇索引,並把索引和數據存放在同一結構中。

在有聚簇索引的表中,索引和行是存放在同一個葉子節點(B-Tree)中的。

"聚簇"表示索引值相鄰的行的存儲位置一般也是相鄰的——一般來說是這樣,但在某些情況下不是。

一張表只能有一個聚簇索引,因爲同一份數據不可能出現兩個地方。

9543190_13053721830jTp.png

圖中展示了一個聚簇索引的示例,需要注意的是:只有葉子節點才包括了數據行的值,非葉子節點只存了索引字段。

在某些DB實現中,可以選擇按照哪個索引做聚簇,但是MySQL的所有存儲都不支持這樣——InnoDB只能按照主鍵做聚簇。

如果表中沒有定義主鍵,InnoDB會選擇一個“非空且有唯一性約束“的索引來做聚簇,如果沒有這樣的索引,則會定義一個不可見的主鍵,並以這個主鍵來聚簇。


從圖中的佈局還可以看到,整個索引以B-Tree方式組織,其中葉子節點包含了行的主鍵值和這一行所有字段的值,非葉子節點只是單純的提供查找路徑信息。

在非主鍵索引中,葉子節點存放的是索引字段的值和一個指向聚簇索引的”行指針“——對應行的主鍵的值。


InnoDB clusters records together only within a page.Pages with adjacent key values may be distant from each other.

InnoDB的聚簇是頁面級別的,即聚簇索引值相鄰的行會被存入同一個頁面,當這個頁面存滿時,接下來的相鄰行會被存入另外一個頁面,而這兩個頁面可能會離的很遠。如圖中的佈局所示,索引值爲1~10的行被存在第一個頁面,11~20的行被存在另外一個頁面,數據被聚簇在單個頁面內,而頁面1和頁面2的磁盤位置卻可能離的很遠。


聚簇的好處:

1. You can keep related data close together——在設計一個郵件系統時,按照(用戶id,郵件id)來做聚簇,同一個用戶的郵件會被存在相鄰的磁盤區域,這樣獲取用戶所有郵件的時候,磁盤IO開銷就很小。

2. Data access is fast——聚簇索引把索引和數據放在同一個B樹中,在以聚簇索引獲取整行數據會很快。

3. Queries that use covering indexes can use the primary key values contained at the leaf node——只要是以聚簇索引爲條件來查找數據,都能利用到”覆蓋索引“這個特性,效率高。


聚簇的不足:

1. 聚簇是數據在磁盤上的組織方式,所以只能帶來磁盤IO上的收益,如果表的數據能全部載入內存,聚簇索引就沒什麼幫助了。

2. 數據插入(Insert)的速度依賴於插入順序——大量數據按照聚簇索引順序插入會很快,如果亂序插入,就會比較慢,並且在大量亂序插入數據後,最好對錶做一次rebuild操作。

3. 更新聚簇索引字段的開銷很大,因爲系統不得不維護所有有關的頁面。

4. 聚簇的數據按照”頁面“來存放,當一個列必須要放入一個已經滿了的頁面時,就會觸發頁面分裂——頁面分裂會帶來附加的IO開銷,也會佔用更多的磁盤空間。

5. 在聚簇的表上做全表掃描會很慢,特別是數據的密集度很低(每個頁面都有大量的空閒項)或因爲多次頁面分裂後,數據存放無序時。

6. 非主鍵索引會比想象中的要大,因爲非主鍵索引除了要存放索引字段,還需要一個指向聚簇索引的入口指針。

7. 以非主鍵索引爲條件訪問不包含在索引中的字段時,需要做2次索引掃描。


The last point can be a bit confusing. Why would a secondary index require two index lookups? The answer lies in the nature of the "row pointers" the secondary index stores. Remember, a leaf node doesn't store a pointer to the referenced row's physical location; rather, it stores the row's primary key values.

That means that to find a row from a secondary index, the storage engine first finds the leaf node in the secondary index and then uses the primary key values stored there to navigate the primary key and find the row. That's double work: two B-Tree navigations instead of one. (In InnoDB, the adaptive hash index can help reduce this penalty.)

爲什麼非主鍵索引需要兩次索引掃描?這關係到非主鍵索引的一個特性——行指針——非主鍵索引的葉子節點存放的不是指向數據行實際物理位置的指針,而是行的主鍵值。

當按照非主鍵索引查找數據時,存儲引擎首先按照非主鍵索引取得對應的”行指針“,然後再按照這個指針查詢主鍵索引獲取整行的值,所以產生了兩次B-Tree查詢。


書中原文以 cluster index和secondary index來區分兩種索引,針對InnoDB,可以直接說成是主鍵和非主鍵。



原文地址:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3639012&highlight=(感謝作者)

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