#Postgres 有幾種索引類型, 並且每個新版本似乎都增加一些新的索引類型。每個索引類型都是有用的,但是具體使用哪種類型取決於(1)資料類型,有時是(2)表中的底層資料和(3)執行的查找類型。接下來的內容我們將介紹在 Postgres 中你可以使用的索引類型,以及何時該使用何種索引類型。在開始之前,這裡有一個我們將帶你親歷的索引類型清單:
B-Tree
倒排索引Generalized Inverted Index (GIN)
倒排搜尋樹Generalized Inverted Seach Tree (GiST)
空間分區的Space partitioned GiST (SP-GiST)
區塊範圍索引Block Range Index (BRIN)
Hash
現在開始介紹索引。
如果你有一個電腦科學的學位,那麼 B-Tree 索引可能是你學會的第一個索引。 B-tree 索引 會建立一個始終保持自身平衡的一棵樹。當它根據索引去尋找某個東西時,它會遍歷這棵樹去找到鍵,然後返回你要找的資料。使用索引是大大快於順序掃描的,因為相對於順序掃描成千上萬的記錄,它可以只需要讀幾個 頁 (當你只返回幾個記錄時)。
如果你執行一個標準的 CREATE INDEX 語句,它將為你建立一個 B-tree 索引。 B-tree 索引在大多數的資料類型上是很有價值的,例如文字、數字和時間戳記。如果你剛開始在你的資料庫中使用索引,並且不在你的資料庫上使用太多的 Postgres 的高級特性,使用標準的 B-Tree 索引可能是你最好的選擇。
GIN 索引,用於多值列倒排索引Generalized Inverted Index,一般稱為 GIN,大多適用於當單一欄位中包含多個值的資料類型。
據 Postgres 文件:
「GIN 設計用於處理被索引的條目是複合值的情況,並且由索引處理的查詢需要搜尋在複合條目中出現的值。例如,這個條目可能是文檔,查詢可以搜尋文件中包含的指定字元。”
包含在這個範圍內的最常見的資料類型有:
hStore
Array
Range
JSONB
關於 GIN 索引中最令人滿意的一件事是,它們能夠理解儲存在複合值中的資料。但是,因為一個 GIN 索引需要有每個被添加的單獨類型的資料結構的特定知識,因此,GIN 索引並不是支援所有的資料類型。
倒排搜尋樹Generalized Inverted Seach Tree(GiST)索引多適用於當你的資料與同一列的其它行資料重疊時。 GiST 索引最好的用處是:如果你宣告一個幾何資料類型,並且你希望知道兩個多邊型是否包含一些點時。在一種情況中一個特定的點可能被包含在一個盒子中,而同時,其它的點僅存在於一個多邊形中。使用 GiST 索引的常見資料類型有:
幾何類型
需要進行全文搜尋的文字類型
GiST 索引在大小上有許多的固定限制,否則,GiST 索引可能會變的特別大。作為其代價,GiST 索引是有損的(不精確的)。
根據官方文件:
「GiST 索引是有損的,這表示索引可能產生虛假匹配,所以需要去檢查真實的表格行去消除虛假匹配。(當需要時 PostgreSQL 會自動執行這個動作)」
這並不意味著你會得到一個錯誤結果,它只是說明了在 Postgres 給你回傳資料之前,會做了一個很小的額外工作來過濾這些虛假結果。
特別提示:同一個資料類型上 GIN 和 GiST 索引往往都可以使用。通常一個有很好的效能表現,但會佔用很大的磁碟空間,反之亦然。說到 GIN 與 GiST 的比較,並沒有某個完美的方案可以適用所有情況,但是,以上規則應用於大部分常見情況。
SP-GiST 索引,用於更大的資料空間分區 GiST (SP-GiST)索引採用來自 Purdue 研究的空間分區樹。 SP-GiST 索引經常用於當你的資料有一個天然的聚集因素,並且不是一個平衡樹的時候。電話號碼是一個非常好的例子 (至少 US 的電話號碼是)。它們有如下的格式:
3 位數字的區域號碼
3 位數字的前綴號 (與先前的電話交換機有關)
4 位元的線路號碼
這意味著第一組前三位有一個天然的聚集因素,接著是第二組三位,然後的數字才是均勻的分佈。但是,在電話號碼的一些區域號中,存在一個比其它區域號更高的飽合狀態。結果可能導致樹非常的不平衡。因為前面有一個天然的聚集因素,而且資料不對等分佈,像電話號碼一樣的資料可能會是 SP-GiST 的一個很好的案例。
區塊範圍索引(BRIN)專注於一些類似 SP-GiST 的情形,它們最好用在當資料有一些自然排序,並且往往資料量很大時。如果有一個以時間為序的 10 億筆的記錄,BRIN 也許就能派上用場。如果你正在查詢一組很大的有自然分組的數據,如有幾個郵編的數據,BRIN 能幫你確保相近的郵編儲存在磁碟上相近的地方。
當你有一個非常大的例如以日期或郵編排序的資料庫, BRIN 索引可以讓你非常快速的跳過或排除一些不需要的資料。此外,與整體資料量大小相比,BRIN 索引相對較小,因此,當你有一個大的資料集時,BRIN 索引可以表現出較好的效能。
Hash 索引, 總算不怕崩潰了Hash 索引在 Postgres 中已經存在多年了,但是,在 Postgres 10 發布之前,對它們的使用一直有個巨大的警告,它不是 WAL-logged 的。這意味著如果你的伺服器崩潰,並且你無法使用如 wal-g 故障轉移到備機或從存檔中恢復,那麼你將丟失那個索引,直到你重建它。隨著 Postgres 10 發布,它們現在是 WAL-logged 的,因此,你可以再次考慮使用它們 ,但是,真正的問題是,你應該這樣做嗎?
Hash 索引有時會提供比 B-Tree 索引更快的查找,並且創建也很快。最大的問題是它們被限制僅用於“相等”的比較操作,因此你只能用於精確匹配的查找。這使得 hash 索引的靈活性遠不及通常使用的 B-Tree 索引,而且,你不能把它看成是一種替代品,而是一種用於特殊情況的索引。
你該使用哪一個?我們剛剛介紹了很多,如果你有點被嚇到,也很正常。如果在你知道這些之前, CREATE INDEX 將始終為你創建使用 B-Tree 的索引,並且有一個好消息是,對於大多數的資料庫, Postgres 的效能都很好或非常好。 :) 如果你考慮使用更多的 Postgres 特性,以下是一個當你使用其它 Postgres 索引類型的備忘清單:
B-Tree - 適用於大多數的資料類型和查詢
GIN - 適用於 JSONB/hstore/arrays
GiST - 適用於全文搜尋和幾何資料類型
SP-GiST - 適用於有天然的聚集因素但是分佈不均勻的大資料集
BRIN - 適用於有順序排列的真正的大數據集
Hash - 適用於相等操作,而且,通常情況下 B-Tree 索引仍然是你所需要的。
如果你有關於這篇文章的任何問題或回饋,歡迎加入我們的 slack channel。
以上是PostgreSQL的探索旅程的詳細內容。更多資訊請關注PHP中文網其他相關文章!