跳轉到內容

PostgreSQL/GIN 索引

來自華夏公益教科書,開放的書本,為開放的世界


GIN(廣義倒排索引)支援可分為較小元件的資料型別,例如陣列的元素、文字文件的單詞或 JSON 物件的屬性。我們稱它們為複合資料型別。與 B 樹不同,GIN 不為完整值生成單個索引條目,而是為每個元件生成一個索引條目。

每個索引條目包含單個元件的值加上元組 ID(TID)。請注意,TID 不包含完整值中元件的序列號。它們只包含資料檔案中的物理頁號加上頁中行的號。

WHERE 子句中可用的運算子取決於資料型別。

  • 陣列:<@(包含於),@>(包含),=(等於),以及 &&(重疊 / 有一些共同元素)。
  • 文字查詢(詞素):@@(包含)。
  • JSON:->(具有給定鍵的 JSON 物件欄位),->>(具有給定鍵的 JSON 物件欄位,作為文字)。

SQL 語法

[編輯 | 編輯原始碼]
-- create a table with a column that holds an array of integers
DROP TABLE IF EXISTS t2;
CREATE TABLE t2 (id INTEGER, arr INTEGER[]);
INSERT INTO t2 VALUES (1,  ARRAY [11, 12, 13]);
INSERT INTO t2 VALUES (2,  ARRAY [21, 22, 23]);

-- insert a lot of other rows to enforce index usage
INSERT INTO t2 (SELECT generate_series(3, 10000, 1), ARRAY[0, 1, 2, 3]);


-- ------------------------------------------
--          create the GIN index
-- ------------------------------------------
CREATE INDEX t2_gin_idx ON t2 USING GIN(arr);


-- use the index
ANALYSE t2;
EXPLAIN SELECT * FROM t2 WHERE arr @> ARRAY[11];

GIN 索引由不同的子結構組成。

  • 元資料頁
  • 一個條目 B 樹
  • 一些釋出 B 樹
  • 一個待處理列表

除其他外,元資料頁包含指向條目 B 樹待處理列表的指標。

條目 B 樹實現了一個樹,其中鍵由原始元件的值組成,例如單個數組元素的值。在非葉級,它們的指標指向下一級的子頁。在葉級,頁面包含兩種型別的條目:首先,有釋出列表。它們由鍵組成,後跟 TID 列表。其次,如果這樣的 TID 列表超過了物理頁面的容量,該列表將被重新排列為一個釋出 B 樹,該樹儲存在一個或多個其他頁面上。原始釋出列表被指向新的釋出 B 樹的指標替換。

釋出 B 樹是部分物理頁面的組成部分,並且包含關於元組 ID 的 B 樹,這些元組 ID 都指向資料檔案中其鍵可以作為其元件之一的值找到的行。

兩種 B 樹型別的實現不同於 PostgreSQL 的標準B 樹實現。

待處理列表是一個頁面列表,其中鍵(元件的值)及其專用的 TID 按順序儲存。待處理列表的存在是為了最佳化目的;見下文。


最佳化

[編輯 | 編輯原始碼]

GIN 索引使用兩種特殊最佳化。首先,如果不同元件(可能在不同的行中)的值經常被使用,則 TID 集將被重新排列為 GIN 內部的 B 樹。考慮許多文字文件的情況:許多詞語很可能在相同和不同的文件中重複使用。在這種情況下,TID 列表可能會增長到數千個,而樹比列表更適合管理它們。

其次,複合資料的INSERTUPDATE會建立許多索引條目:每個元件一個,例如文字中的每個詞一個。在第一步中,這些新的索引條目被收集在索引樹之外的單獨待處理列表中(與原始CREATE INDEX命令相反)。在下一個VACUUM執行期間,這些條目使用在初始索引建立期間使用的相同批次插入技術從待處理列表移動到 GIN 樹結構中。這種批次技術加速了該過程,而且更有用的是,工作被委託給後臺程序。當然,也存在缺點:除了遍歷索引樹之外,每個查詢都必須掃描待處理列表。

[編輯 | 編輯原始碼]

關於 GIN 的 PostgreSQL 文件
關於 GIN 實現的 PostgreSQL 文件


華夏公益教科書