二級索引(輔助索引、非聚簇索引)
在MySQL中,一個數(shù)據(jù)表只能有一個聚簇索引,但是可以有多個二級索引
上邊介紹的聚簇索引只能在搜索條件是主鍵值時才能發(fā)揮作用,因為B+樹中的數(shù)據(jù)都是按照主鍵進行排序的。那如果我們想以別的列作為搜索條件該怎么辦呢?肯定不能是從頭到尾沿著鏈表依次遍歷記錄一遍。
答案:我們可以多建幾棵B+樹,不同的B+樹中的數(shù)據(jù)采用不同的排序規(guī)則。比方說我們用 c2 列的大小作為數(shù)據(jù)頁、頁中記錄的排序規(guī)則,再建一棵B+樹,效果如下圖所示:
[圖片上傳失敗...(image-865c34-1714228781081)]
這個B+樹與上邊介紹的聚簇索引有幾處不同:
- 使用記錄c2列的大小進行記錄和頁的排序,這包括三個方面的含義:
- 頁內(nèi)的記錄是按照c2列的大小順序排成一個 單向鏈表 。
- 各個存放 用戶記錄的頁 也是根據(jù)頁中記錄的c2列大小順序排成一個 雙向鏈表 。
- 存放目錄項記錄的頁分為不同的層次,在同一層次中的頁也是根據(jù)頁中目錄項記錄的c2列大小順序排成一個雙向鏈表。
- B+樹的葉子節(jié)點存儲的并不是完整的用戶記錄,而只是c2列+主鍵這兩個列的值。
- 目錄項記錄中不再是主鍵+頁號的搭配,而變成了c2列+頁號的搭配。
所以如果我們現(xiàn)在想通過c2列的值查找某些記錄的話就可以使用我們剛剛建好的這個B+樹了。以查找c2列的值為4的記錄為例,查找過程如下:
-
確定目錄項記錄頁
根據(jù)根頁面,也就是頁44,可以快速定位到目錄項記錄所在的頁為頁42(因為2< 4<9 )。
-
通過 目錄項記錄頁 確定用戶記錄真實所在的頁。
在頁42中可以快速定位到實際存儲用戶記錄的頁,但是由于c2列并沒有唯一性約束,所以c2列值為4的記錄可能分布在多個數(shù)據(jù)頁中,又因為2< 4≤4,所以確定實際存儲用戶記錄的頁在頁34和頁35中。
-
在真實存儲用戶記錄的頁中定位到具體的記錄。
到頁34和頁35中定位到具體的記錄。
但是這個B+樹的葉子節(jié)點中的記錄只存儲了c2和c1(也就是主鍵)兩個列,所以我們必須再根據(jù)主鍵值去聚簇索引中再查找—遍完整的用戶記錄。
概念:回表
我們根據(jù)這個以c2列大小排序的B+樹只能確定我們要查找記錄的主鍵值,所以如果我們想根據(jù)c2列的值查找到完整的用戶記錄的話,仍然需要到聚簇索引中再查一遍,這個過程稱為回表。也就是根據(jù)c2列的值查詢一條完整的用戶記錄需要使用到2棵B+樹!
問題:為什么我們還需要一次 回表 操作呢?直接把完整的用戶記錄放到葉子節(jié)點不OK嗎?
回答:
如果把完整的用戶記錄放到葉子節(jié)點是可以不用回表。但是太占地方了,相當于每建立一棵B+樹都需要把所有的用戶記錄再都拷貝一遍,這就有點太浪費存儲空間了。
因為這種按照 非主鍵列 建立的B+樹需要一次回表操作才可以定位到完整的用戶記錄,所以這種B+樹也被稱為二級索引(英文名secondary index ) ,或者輔助索引 。由于我們使用的是c2列的大小作為B+樹的排序規(guī)則,所以我們也稱這個B+樹是為c2列建立的索引。
非聚簇索引的存在不影響數(shù)據(jù)在聚簇索引中的組織,所以一張表可以有多個非聚簇索引。
[圖片上傳失敗...(image-b7c805-1714228781081)]
小結:聚簇索引與非聚簇索引的原理不同,在使用上也有一些區(qū)別:
- 聚簇索引的 葉子節(jié)點 存儲的就是我們的 數(shù)據(jù)記錄,非聚簇索引的葉子節(jié)點存儲的是 數(shù)據(jù)位置 。非聚簇索引不會影響數(shù)據(jù)表的物理存儲順序。
- 一個表只能有一個聚簇索引,因為只能有一種排序存儲的方式,但可以有多個非聚簇索引,也就是多個索引目錄提供數(shù)據(jù)檢索。
- 使用聚簇索引的時候,數(shù)據(jù)的查詢效率高 ,但如果對數(shù)據(jù)進行插入,刪除,更新等操作,效率會比非聚簇索引低。