Hash索引


一、兩種類型的Hash表

  • Hash表:假設有編號為 0 到 B-1 的B個位置(桶)存放數據,使用一個Hash函數,把需要存儲的數據作為參數計算一個介於 0 到 B-1的值,將這個數據存放到這個值對應的位置(桶),所有數據存放完畢,則形成一張Hash表

1.靜態Hash表

桶數目B不變

2. 動態Hash表:

  桶數據允許改變,動態Hash表分為分為兩種

2.1 可擴展Hash表

  • 為桶增加一個中間層,即使用一個指針數組來表示桶,而不是直接使用數據快作為桶。指針指向具體存儲數據的數據塊
  • 指針數組能增長,數組長度總是2的冪。每增長一次,指針數組長度翻倍
  • Hash函數為每個鍵值計算出一個足夠長的二進制序列,使用二進制序列中從第一位開始的若干位作為鍵的Hash值,這個值對應的就是一個指針

2.2 線性Hash表

  • 桶數B由需要存儲的記錄數決定
  • 用於標識桶數的二進制位數為[log2B]
  • 桶的增長較為緩慢。
  • 如何插入元組:計算元組的Hash值,設這個值為K。假設此時[log2B]的值為i。將K轉換為二進制數,從右開始取i位,得到的數即為元組要放入的桶數

二. postgresql中用做索引的Hash表為線性Hash表

  Hash表有四種不同類型的頁面,分別為元頁、桶頁、溢出頁、位圖頁:

 

 

 

1 元頁:

  • 每個Hash索引都有一個元頁。元頁為索引的0號頁,不屬於任何桶。
  • 元頁記錄了Hash的版本號、Hash索引記錄的索引元組數目以及桶和位圖的信息。
  • 通過元頁可以了解Hash索引總體使用情況,在索引的插入,溢出頁的分配回收以及Hash表的擴展等過程中,都要用到元頁

數據結構和各成員意義如下:

 

 

 2.桶頁

  • Hash表有多個桶,每個桶由一個或多個頁組成,每個桶的第一頁稱為桶頁,其他頁稱為溢出頁。
  • 桶頁隨着桶的建立而建立,如果有溢出頁,則桶頁結構中的hasho_nextblkno字段指向溢出頁,形成鏈結構
  • 桶頁的分配:splitpoint值修改時,將進行桶的分配,每次分配的數目都是2的冪次。0號和1號桶時Hash表初始化時候分配的,當splitpoint為2時,進行一次分配,將同時分配2號、3號桶頁。當需要第5個桶時,splitpoint值為3,將分配4~7號桶頁,依此類推。每次分配桶頁時候,也會在桶頁后按需求分配一定數量的溢出頁,溢出頁數量記錄在hashm_spare數組中
  • 每次分配的桶頁在磁盤上是連續存儲的,因此,可以根據桶頁數計算桶所對應的磁盤塊號:

注:hashm_spare記錄第i次分裂后溢出頁個數和位圖頁個數的和

 

 

 3.溢出頁

  • 當某個元組在它所屬的桶中放不下時,就需要將其放在該桶的溢出頁。溢出頁和桶頁之間使用雙向鏈表連接。
  • 元頁中使用數組hashm_spares記錄每次桶的擴展時分配的溢出頁數
  • 溢出頁一旦分配,便一直存在,即使被回收也只是標記為空閑,並沒有釋放物理空間

4.位圖

  當溢出頁上的元組被移除時,就要將溢出頁回收,回收溢出頁並不是把它還給操作系統,而是繼續由PostgreSQL管理,以便下一次需要時使用。因此需要一種機制來記錄每一個溢出頁是否可用。

  • 用於管理Hash索引溢出頁和位圖頁本身的使用情況
  • 在位圖中,對於每個溢出頁和位圖頁都有一個比特位標識其使用情況。0表示該頁可用,1表示該頁不可用。位圖頁的格式由頁頭PageHeaderData,頁尾Special Space和中間的位數組組成,中間的位數組的每一位對應一個溢出頁或位圖。位圖中的位數必須為2的冪次

 

  •  通過元頁中的hashm_mapp數組可以找到位圖對應的塊號
  • 利用元頁中的hashm_mapp以及上面提到的hashm_spares可以快速查找到空閑溢出頁

5.Hash表頁面分配示例:

1.初始化

 

 

2.為0號桶分配溢出頁0和溢出頁1:

 

 3.增加一個桶

 

 4.為2號桶增加一個溢出頁

 

 三.Hash索引的實現

1.Hash表的創建:

  1. 初始化索引的元頁、桶以及位圖頁
  2. 調用掃描函數對待索引的表進行掃描,生成索引元組
  3. 將索引元組插入到Hash表

2.元組的插入:

讀取元組的信息,計算該索引元組應插入的桶號,若該桶有足夠的空間,則直接插入,否則申請溢出頁。完成插入后,系統根據元頁信息判斷是否需要增加新的桶

 

 

3.溢出頁的分配和回收

索引元組插入過程中如果桶中沒有空間,就需要創建一個溢出頁存放索引元組。當對Hash表進行擴展后,原來存放在溢出頁中的索引元組可能會被移入到新增加的桶中,這時就需要對溢出頁進行回收。

溢出頁的分配:

 

 溢出頁的回收

 

 

4. Hash表的擴展

每次插入后,用當前記錄總數 r 和當前桶數目相除,計算 r/n ,若比率太大,則對Hash表進行擴展,即增加一個桶到Hash表中。如果新加入的桶的桶號二進制表示為1a2a3......ai,那么就試圖分裂桶號為0a2a3......a的桶的元組,這個桶中部分元組(計算Hash值,取i+1位后,第一位為1的元組)將被移動到新的桶中

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM