PostgreSQL 包含持久化磁碟雜湊索引的實作,該索引是完全可從崩潰中恢復的。任何資料類型都可以通過雜湊索引建立索引,包括沒有明確定義線性排序的資料類型。雜湊索引僅儲存被索引資料的雜湊值,因此對被索引的資料欄位的大小沒有限制。
雜湊索引僅支援單欄索引,並且不允許唯一性檢查。
雜湊索引僅支援 =
運算子,因此指定範圍運算的 WHERE 子句將無法利用雜湊索引。
每個雜湊索引元組僅儲存 4 位元組的雜湊值,而不是實際的欄位值。 因此,在索引較長的資料項目(例如 UUID、URL 等)時,雜湊索引可能比 B 樹小得多。 缺少欄位值也使所有雜湊索引掃描都具有損耗性。 雜湊索引可以參與位元圖索引掃描和向後掃描。
雜湊索引最適合在較大表格上使用等式掃描的 SELECT 和 UPDATE 密集型工作負載。 在 B 樹索引中,搜尋必須遍歷樹,直到找到葉節點頁面。 在具有數百萬列的表格中,此遍歷會增加資料的存取時間。 雜湊索引中葉節點頁面的等效項稱為儲存桶頁面。 相比之下,雜湊索引允許直接存取儲存桶頁面,從而可能減少較大表格中的索引存取時間。 這種「邏輯 I/O」的減少在索引/資料大於 shared_buffers/RAM 時變得更加明顯。
雜湊索引經過設計,可以應付雜湊值分佈不均的情況。 如果雜湊值分佈均勻,則直接存取儲存桶頁面效果良好。 當插入意味著儲存桶頁面已滿時,會將額外的溢位頁面鏈接到該特定儲存桶頁面,以在本地擴展與該雜湊值匹配的索引元組的儲存空間。 在查詢期間掃描雜湊儲存桶時,我們需要掃描所有溢位頁面。 因此,對於某些資料,就所需的區塊存取次數而言,不平衡的雜湊索引實際上可能比 B 樹更差。
由於溢位的情況,我們可以說雜湊索引最適合於唯一、幾乎唯一的資料或每個雜湊儲存桶的列數較少的資料。 避免問題的一種可能方法是使用部分索引條件從索引中排除高度非唯一的值,但在許多情況下這可能並不合適。
與 B 樹一樣,雜湊索引執行簡單的索引元組刪除。 這是一個延遲維護操作,它會刪除已知可以安全刪除的索引元組(那些項目識別碼的 LP_DEAD 位已設定的元組)。 如果插入時發現頁面上沒有可用空間,我們會嘗試通過刪除無效的索引元組來避免建立新的溢位頁面。 如果頁面當時被鎖定,則無法進行刪除。 刪除無效的索引指標也會在 VACUUM 期間發生。
如果可以,VACUUM 也會嘗試將索引元組壓縮到盡可能少的溢位頁面上,從而最大限度地減少溢位鏈。 如果溢位頁面變為空,則可以回收溢位頁面以在其他儲存桶中重複使用,儘管我們永遠不會將它們返回到作業系統。 目前沒有縮小雜湊索引的規定,只能使用 REINDEX 重建。 也沒有減少儲存桶數量的規定。
隨著索引列數的增加,雜湊索引可能會擴展儲存桶頁面的數量。 選擇雜湊鍵到儲存桶編號的對應,以便可以逐步擴展索引。 當要將新儲存桶新增到索引時,將需要「分割」一個現有儲存桶,並且根據更新的鍵到儲存桶編號的對應,將其某些元組傳輸到新儲存桶。
擴展在前台發生,這可能會增加使用者插入的執行時間。 因此,雜湊索引可能不適用於列數快速增加的表格。
雜湊索引中有四種類型的頁面:元頁面(第零頁),包含靜態分配的控制資訊;主要儲存桶頁面;溢位頁面;以及位元圖頁面,用於追蹤已釋放且可用於重複使用的溢位頁面。 出於定址目的,位元圖頁面被視為溢位頁面的子集。
掃描索引和插入元組都需要找到應該放置給定元組的儲存桶。 為此,我們需要來自元頁面的儲存桶計數、highmask 和 lowmask;但是,出於效能原因,不希望每次此類操作都必須鎖定和固定元頁面。 相反,我們在每個後端的 relcache 條目中保留元頁面的快取副本。 只要自上次快取更新以來目標儲存桶尚未分割,這將產生正確的儲存桶對應。
主要儲存桶頁面和溢位頁面是獨立分配的,因為相對於其儲存桶數量,任何給定的索引可能需要或多或少的溢位頁面。 雜湊碼使用一組有趣的定址規則來支援可變數量的溢位頁面,而無需在建立主要儲存桶頁面後移動它們。
表格中索引的每一列都由雜湊索引中的單個索引元組表示。 雜湊索引元組儲存在儲存桶頁面中,如果存在,則儲存在溢位頁面中。 我們通過使任何一個索引頁面中的索引條目按雜湊碼排序來加速搜尋,從而允許在索引頁面內使用二進位搜尋。 但是請注意,*沒有*關於儲存桶不同索引頁面之間雜湊碼相對排序的假設。
擴展雜湊索引的儲存桶分割演算法太複雜了,不值得在此提及,儘管在 src/backend/access/hash/README
中有更詳細的描述。 分割演算法具有防崩潰功能,如果未成功完成,可以重新啟動。
如果您在文件中發現任何不正確、與您的特定功能使用經驗不符或需要進一步澄清的地方,請使用此表單回報文件問題。