每個索引對應於InnoDB中的壹個B+樹。
假設我們有壹個表,它的主鍵列是ID,表中有壹個字段K,K上有壹個索引..
該表的建表語句為:
表中R1~R5的(ID,k)值分別為(100,1),(200,2),(300,3),(500,5),(600,6)。兩棵樹的示意圖如下。
從圖中不難看出,索引類型根據葉節點的內容分為主鍵索引和非主鍵索引。
主鍵索引的葉節點存儲整行數據。在InnoDB中,主鍵索引也稱為聚集索引。
非主鍵索引的葉節點內容是主鍵的值。在InnoDB中,非主鍵索引也稱為二級索引或普通索引。
根據上面的索引結構描述,我們來討論壹個問題:基於主鍵索引的查詢和基於普通索引的查詢有什麽區別?
換句話說,基於非主鍵索引的查詢需要多掃描壹棵索引樹。這就是為什麽我們應該嘗試使用主鍵查詢。
為了維護索引順序,插入新值時需要維護B+樹。以上圖為例。如果新的行ID值是700,您只需要在R5的記錄之後插入壹條新記錄。如果新插入的ID值是400,就比較麻煩,需要邏輯上把數據後移,騰出空間。
更糟糕的是,如果R5所在的數據頁已經滿了,按照B+樹的算法,這時候就需要申請新的數據頁,然後再移動壹部分數據。這個過程稱為頁面拆分。這種情況下,性能自然會受到影響。
除了性能之外,頁拆分操作也會影響數據頁的利用率。原來放在壹個頁面的數據,現在分成兩個頁面,整體空間利用率降低了50%左右。
當然有分,也有合並。當兩個相鄰頁面由於數據被刪除而導致利用率較低時,數據頁面將被合並。合並的過程可以看作是分割過程的逆過程。
基於以上對索引維護流程的描述,我們來討論壹個案例:
妳可能在壹些建表規範中看到過類似的描述,要求建表語句中必須有壹個自增主鍵。當然,沒有什麽是絕對的。我們來分析壹下哪些場景應該使用自增主鍵,哪些場景不應該。
自加主鍵是指在自加列上定義的主鍵,壹般在建表語句中定義:
插入新記錄時,不需要指定ID的值,系統會得到當前最大ID加上1作為下壹條記錄的ID值。
換句話說,自增主鍵的數據插入模式正好符合我們前面提到的增量插入場景。每次插入新記錄都是加法操作,不涉及移動其他記錄,也不會觸發葉節點的劃分。
當壹個有業務邏輯的字段作為主鍵時,往往很難保證有序插入,所以寫數據的成本比較高。
除了考慮性能,還可以從存儲空間的角度來看。假設您的表中確實有壹個唯壹的字段,比如字符串類型的ID號,您應該使用ID號作為主鍵還是使用自增字段作為主鍵?
因為每個非主鍵索引的葉節點就是主鍵的值。如果用ID號作為主鍵,每個二級索引的葉節點占用20個字節左右,而如果用整數作為主鍵,只需要4個字節,如果是bigint,就是8個字節。
顯然,主鍵的長度越小,普通索引的葉節點就越小,普通索引占用的空間也就越小。
所以考慮到性能和存儲空間,自增主鍵往往是更合理的選擇。
有沒有適合直接用業務字段做主鍵的場景?還是有的。例如,某些業務的場景需求如下:
妳壹定看到了,這是典型的KV場景。
由於沒有其他索引,所以不需要考慮其他索引的葉節點大小。
這時候就要優先考慮“盡可能使用主鍵查詢”的原則,直接將這個索引設置為主鍵,這樣就避免了每次都要搜索兩棵樹。
-從極客時間中學習