PostgreSQL DBA(49) - Index(SP-GiST)

husthxd發表於2019-07-05

本節簡單介紹了PostgreSQL中的SP-GiST索引,包括SP-GiST索引的基礎知識和結構等.

簡介
上一節介紹了GiST索引,SP-GiST基於GiST,其中SP的意思是 space partitioning ,這裡的space是指日常生活我們稱之為空間的space,比如二維平面(two-dimensional plane)等.
SP-GiST適用於空間可遞迴分割為N個互不相交區域的結構,包括quadtrees/k-dimensional trees(k-D trees)/radix trees.

結構
SP-GiST的訪問方法是分割值域為互不相交的子域,這些子域可遞迴分割.這樣的劃分方法生成的樹是非平衡樹(Btree和GiST是平衡樹).
互不相交的特性簡化了插入和檢索的複雜度.換句話說,樹的分支率比較低.比如,一棵quadtree的某個節點通常有4個位元組點(Btree可能有上百個)以及更深的高度.這種型別的樹比較適合在記憶體中操作,但索引是儲存在磁碟上面的,因此為了減少I/O,節點必須打包到pages中,要有效地做到這一點並不容易.除此之外,由於分支深度的不同,在索引中查詢不同值所需的時間也有所不同.
AM(access method)訪問方法,與GiST類似,處理低層次的任務(併發訪問和鎖定/日誌記錄/純搜尋演算法)並提供指定的簡化介面以便為新資料型別和新分割槽演算法提供支援.

SP-GiST樹的內部節點儲存子節點的引用, label 為每個參考定義.除此之外,內部節點可儲存稱為”prefix”的值,實際上這個值不是字首;它可以看作是滿足所有子節點的任意謂詞.
葉子節點包含索引型別值和TID的引用.索引資料本身(搜尋鍵)可以用作值,但這不是必需的:可以儲存縮短的值.
另外,葉子節點可被分組為連結串列,因此內部節點可以參考一個值而不是整個連結串列.
注意葉子節點中的 prefixs,labels 有自己的資料型別,與其他節點相對獨立.

與GiST一樣,定義檢索的主函式是 consistency function ,處理邏輯與GiST類似.

在物理儲存上面,索引節點被打包為pages,這樣可以在處理節點進行I/O時可以更高效,一個page可以包含內部或葉子節點,但不能既包含內部也包含葉子節點.

示例:quadtree
quadtree用於索引平面上的點,一種常用的做法是遞迴的將區域相對於中心點劃分為四個部分(象限),在這樣一棵樹上,分支的深度可以變化,這取決於相應象限中點的密度.
舉個例子:
First, we split the plane into four quadrants

Then we split each of the quadrants

And so on until we get the final partitioning

下面是一個更簡單的例子,如下圖所示:

在該例中,4個象限編號為1-4,為了清晰起見,按照完全相同的順序從左到右放置子節點,其中一種索引結構如下圖所示:

每一個內部節點引用(指向)四個子節點中最大的那個.每一個引用使用象限編號打標記(如上圖所示).但實現上沒有標記存在,因為儲存固定的陣列更方便,其中一些引用還可能是空的.

沿用上一節使用的points資料表,建立SP-GiST索引:


testdb=# create index idx_points_quad_idx on points using spgist(p);
CREATE INDEX

預設使用quad_point_ops op class,包含以下operators:


testdb=# select amop.amopopr::regoperator, amop.amopstrategy
testdb-# from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
testdb-# where opc.opcname = 'quad_point_ops'
testdb-# and opf.oid = opc.opcfamily
testdb-# and am.oid = opf.opfmethod
testdb-# and amop.amopfamily = opc.opcfamily
testdb-# and am.amname = 'spgist'
testdb-# and amop.amoplefttype = opc.opcintype;
     amopopr      | amopstrategy 
------------------+--------------
 <<(point,point)  |            1
 >>(point,point)  |            5
 ~=(point,point)  |            6
 <^(point,point)  |           10
 >^(point,point)  |           11
 <->(point,point) |           15
 <@(point,box)    |            8
(7 rows)

下面希望找到(2,7)上的點,即:

搜尋過程是從root節點開始,使用 consistency function 選擇沿哪個子節點向下搜尋,對於操作符”>^”,函式比較(2,7)和中心點(4,4)選擇可能包含目標點的象限(在本例中是第一和第四象限),在第一象限,使用 consistency function 確定沿哪個子節點向下搜尋,第一象限的中心點是(6,6),因此繼續搜尋第一和第四象限(該象限為空),葉子節點(8,6)和(7,8)在第一象限中,只有(7,8)滿足查詢條件,返回結果同時回到上一層檢索中心點(4,4)的第四象限,該象限為空,深度遍歷結束.


testdb=# set enable_seqscan = off;
SET
testdb=# explain (costs off) select * from points where p >^ point '(2,7)';
                     QUERY PLAN                      
-----------------------------------------------------
 Index Only Scan using idx_points_quad_idx on points
   Index Cond: (p >^ '(2,7)'::point)
(2 rows)
testdb=# select * from points where p >^ point '(2,7)';
   p   
-------
 (7,8)
(1 row)

參考資料
Indexes in PostgreSQL — 6 (SP-GiST)

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/6906/viewspace-2649664/,如需轉載,請註明出處,否則將追究法律責任。

相關文章