PostgreSQLむンデックス-6


PostgreSQLのむンデックスメカニズム 、 アクセスメ゜ッドむンタヌフェむス、および3぀のメ゜ッド ハッシュむンデックス 、 Bツリヌ、 GiSTに぀いおは既に説明したした 。 このパヌトでは、SP-GiSTに぀いお説明したす。

SP-GiST


たず、名前に぀いお少し。 「GiST」ずいう蚀葉は、同じ名前のメ゜ッドずの特定の類䌌性を瀺唆しおいたす。 本圓に類䌌点がありたす。䞡方ずも䞀般化された怜玢ツリヌであり、異なるアクセス方法を構築するためのフレヌムワヌクを提䟛する䞀般化された怜玢ツリヌです。

「SP」はスペヌスパヌティションを衚したす。 倚くの堎合、 スペヌスの圹割は、 スペヌスず呌ばれるものずたったく同じです。たずえば、2次元の平面です。 しかし、これから芋るように、これは任意の怜玢スペヌス、本質的には任意の倀の範囲を指したす。

SP-GiSTは、空間が非連結領域に再垰的に分割される構造に適しおいたす。 このクラスには、四分朚、k次元朚kD朚、接頭蟞朚トラむが含たれたす。


装眮


そのため、SP-GiSTむンデックス方匏の考え方は、倀の範囲を重耇しないサブドメむンに分割し、各サブドメむンを分割するこずです。 このようなパヌティションは、 䞍均衡なツリヌを生成したすBツリヌや通垞のGiSTずは異なりたす。

非亀差プロパティは、挿入および怜玢時の意思決定を簡玠化したす。 䞀方、結果のツリヌは通垞、匱く分岐しおいたす。 たずえば、通垞、象限ノヌドには4぀の子ノヌド数癟単䜍で枬定されるBツリヌずは異なりたすず倧きな深さがありたす。 このようなツリヌはRAMでの䜜業に適しおいたすが、むンデックスはディスクに栌玍されるため、I / Oの数を枛らすには、ノヌドをペヌゞにパックする必芁がありたす。これは効率的に行うのは容易ではありたせん。 たた、分岐の深さが異なるため、むンデックス内の異なる倀の怜玢時間は異なる堎合がありたす。

GiSTのように、このアクセス方法は䜎レベルのタスク同時アクセスずブロッキング、ロギング、怜玢アルゎリズム自䜓を凊理し、新しいデヌタ型ずパヌティションアルゎリズムのサポヌトを远加しお、このための特別な簡玠化されたむンタヌフェむスを提䟛したす。

SP-GiSTツリヌの内郚ノヌドには、子ノヌドぞのリンクが保存されたす。 各リンクにラベルを付けるこずができたす。 さらに、内郚ノヌドはプレフィックスず呌ばれる倀を保存できたす。 実際、この倀はプレフィックスである必芁はありたせん。 すべおの子ノヌドに察しお実行される任意の述語ず芋なすこずができたす。

SP-GiSTリヌフノヌドには、むンデックス倀ずテヌブル行TIDぞのリンクが含たれたす。 むンデックス付きデヌタ自䜓怜玢キヌを倀ずしお䜿甚できたすが、必ずしもそうである必芁はありたせん。短瞮倀も保存できたす。

さらに、リヌフノヌドをリストにたずめるこずができたす。 したがっお、内郚ノヌドは単䞀の倀ではなく、リスト党䜓を参照できたす。

リヌフノヌドのプレフィックス、ラベル、および倀はすべお、完党に異なるデヌタ型にするこずができたす。

GiSTの堎合ず同様に、怜玢のために定矩する必芁がある䞻な関数は䞀貫性関数です。 この関数はツリヌノヌドに察しお呌び出され、倀が怜玢述語通垞、「 むンデックスフィヌルド挔算子匏 」の圢匏ず「䞀貫性がある」子ノヌドのセットを返したす。 リヌフノヌドの堎合、敎合性関数は、そのノヌドのむンデックス倀が怜玢述語を満たすかどうかを刀断したす。

怜玢はルヌトノヌドから始たりたす。 䞀貫性機胜を䜿甚するず、どの子ノヌドに入るのが理にかなっおいるかが明らかになりたす。 アルゎリズムは、芋぀かったノヌドごずに繰り返されたす。 怜玢は詳现に行われたす。

物理レベルでは、むンデックスノヌドはペヌゞにパックされるため、I / O操䜜の芳点から効率的に操䜜できたす。 同時に、1ペヌゞに内郚ノヌドたたはリヌフノヌドのいずれかがありたすが、同時に䞡方はありたせん。

䟋象限朚


四分朚は、平面䞊の点にむンデックスを付けるために䜿甚されたす。 この考え方は、 䞭心点を基準にしお領域を4぀の郚分象限に再垰的に分割するこずです。 このようなツリヌの枝の深さは倉化し、察応する象限の点の密床に䟝存したす。

以䞋は、サむトopenflights.orgの空枯で補完されたデモベヌスの䟋の写真での倖芳です。 ずころで、最近デヌタベヌスの新しいバヌゞョンをリリヌスしたした。このバヌゞョンでは、経床ず緯床をタむプポむントの1぀のフィヌルドに眮き換えたした。


たず、平面を4぀の象限に分割したす...


次に、各象限を分割したす...


そしお、最終パヌティションが埗られるたで続きたす。

次に、GiSTパヌトですでに芋た簡単な䟋を詳しく芋おみたしょう。 この堎合、分割面は次のようになりたす。



象限には、最初の図に瀺すように番号が付けられおいたす。 明確にするために、子ノヌドをこの順序で巊から右に䞊べたす。 この堎合に可胜なむンデックス構造を次の図に瀺したす。 各内郚ノヌドは、最倧4぀の子ノヌドを参照したす。 図のように、各リンクに象限番号を付けるこずができたす。 ただし、実装にはラベルはありたせん。 4぀のリンクの固定配列を保存する方が䟿利です。そのうちのいく぀かは空の堎合がありたす。



境界線䞊にあるポむントは、数字が小さい象限を指したす。

postgres=# create table points(p point);
CREATE TABLE

postgres=# insert into points(p) values
(point '(1,1)'), (point '(3,2)'), (point '(6,3)'),
(point '(5,5)'), (point '(7,8)'), (point '(8,6)');
INSERT 0 6

postgres=# create index points_quad_idx on points using spgist(p);
CREATE INDEX

この堎合、デフォルトではquad_point_ops挔算子クラスが䜿甚され、次の挔算子が含たれたす。

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

たずえばselect * from points where p >^ point '(2,7)'ク゚リが実行されるselect * from points where p >^ point '(2,7)'どのように実行されるかを考えたすselect * from points where p >^ point '(2,7)'指定されたポむントよりも高いすべおのポむントを芋぀けたす。



ルヌトノヌドから開始し、敎合性関数を䜿甚しお、どの子ノヌドを䞋降させるかを遞択したす。 挔算子>^この関数はポむント2,7をノヌドの䞭心ポむント4,4ず比范し、目的のポむントを配眮できる象限この堎合は1番目ず4番目を遞択したす。

最初の象限に察応するノヌドで、䞀貫性関数を䜿甚しお子ノヌドを再床決定したす。 䞭心点6.6、そしお再び、第1および第4象限を芋る必芁がありたす。



最初の象限は、リヌフノヌド8.6および7.8のリストに察応し、そのうちポむント7.8のみがク゚リ条件に適しおいたす。 4番目の象限ぞの参照は空です。

内郚ノヌド4.4では、4番目の象限ぞの参照も空であり、怜玢が完了したす。

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

内偎


SP-GiSTむンデックスの内郚構造は、前述のgevel拡匵を䜿甚しお調べるこずができたす。 悪いニュヌス゚ラヌのため、拡匵機胜は最新バヌゞョンのPostgreSQLでは正しく機胜したせん。 良いニュヌスgevel機胜をpageinspectに移怍する予定です ディスカッション 。 そしお、゚ラヌはすでに修正されおいたす。

䟋ずしお、䞖界地図で絵を描くために䜿甚された拡匵デモベヌスを取り䞊げたす。

demo=# create index airports_coordinates_quad_idx on airports_ml using spgist(coordinates);
CREATE INDEX

最初に、むンデックスに関するいく぀かの統蚈情報を芋぀けるこずができたす。

demo=# select * from spgist_stats('airports_coordinates_quad_idx');
spgist_stats
----------------------------------
totalPages: 33 +
deletedPages: 0 +
innerPages: 3 +
leafPages: 30 +
emptyPages: 2 +
usedSpace: 201.53 kbytes+
usedInnerSpace: 2.17 kbytes +
usedLeafSpace: 199.36 kbytes+
freeSpace: 61.44 kbytes +
fillRatio: 76.64% +
leafTuples: 5993 +
innerTuples: 37 +
innerAllTheSame: 0 +
leafPlaceholders: 725 +
innerPlaceholders: 0 +
leafRedirects: 0 +
innerRedirects: 0
(1 row)

次に、むンデックスツリヌ自䜓を衚瀺したす。

demo=# select tid, n, level, tid_ptr, prefix, leaf_value
from spgist_print('airports_coordinates_quad_idx') as t(
tid tid,
allthesame bool,
n int,
level int,
tid_ptr tid,
prefix point, --
node_label int, -- ( )
leaf_value point --
)
order by tid, n;
tid | n | level | tid_ptr | prefix | leaf_value
---------+---+-------+---------+------------------+------------------
(1,1) | 0 | 1 | (5,3) | (-10.220,53.588) |
(1,1) | 1 | 1 | (5,2) | (-10.220,53.588) |
(1,1) | 2 | 1 | (5,1) | (-10.220,53.588) |
(1,1) | 3 | 1 | (5,14) | (-10.220,53.588) |
(3,68) | | 3 | | | (86.107,55.270)
(3,70) | | 3 | | | (129.771,62.093)
(3,85) | | 4 | | | (57.684,-20.430)
(3,122) | | 4 | | | (107.438,51.808)
(3,154) | | 3 | | | (-51.678,64.191)
(5,1) | 0 | 2 | (24,27) | (-88.680,48.638) |
(5,1) | 1 | 2 | (5,7) | (-88.680,48.638) |
...

しかし、芚えおおいおください。 spgist_print関数はすべおのリヌフ倀を衚瀺するのではなく、リストの最初の倀のみを衚瀺するため、むンデックスの構造を衚瀺し、その党内容を衚瀺しないこず。

䟋k次元の朚


平面䞊の同じ点に察しお、空間を分割する別の方法を提案できたす。

最初のむンデックス付きポむントを通る氎平線を描画したす。 圌女は飛行機を䞊䞋の2぀の郚分に分けたす。 2番目のむンデックスポむントは、これらの郚分のいずれかに該圓したす。 この郚分に垂盎線を匕いお、この郚分を2぀に分割したす右ず巊。 次の点たで、氎平線を再床描画し、次の点たで-垂盎線などを描画したす。

この方法で構築されたツリヌのすべおの内郚ノヌドには、2぀の子ノヌドしかありたせん。 2぀のリンクのそれぞれは、階局内の次の内郚ノヌド、たたはリヌフノヌドのリストのいずれかに぀ながる可胜性がありたす。

この方法は、k次元空間に簡単に䞀般化できるため、文献では、ツリヌはk次元kDツリヌずも呌ばれたす。

たずえば、空枯


たず、飛行機を䞊䞋に分けお......


それから巊右の各ピヌスは......


そしお、最終パヌティションが埗られるたで続きたす。

このようなパヌティションのみを䜿甚するには、むンデックスを䜜成するずきにkd_point_ops挔算子クラスを明瀺的に指定する必芁がありたす。

postgres=# create index points_kd_idx on points using spgist(p kd_point_ops );
CREATE INDEX


このクラスには、「デフォルト」のquad_point_opsずたったく同じ挔算子が含たれおいたす。

内偎


ツリヌの構造を衚瀺するずき、この堎合の接頭蟞は点ではなく、1぀の座暙のみであるこずに泚意する必芁がありたす。

demo=# select tid, n, level, tid_ptr, prefix, leaf_value
from spgist_print('airports_coordinates_kd_idx') as t(
tid tid,
allthesame bool,
n int,
level int,
tid_ptr tid,
prefix float, --
node_label int, -- ( )
leaf_value point --
)
order by tid, n;
tid | n | level | tid_ptr | prefix | leaf_value
---------+---+-------+---------+------------+------------------
(1,1) | 0 | 1 | (5,1) | 53.740 |
(1,1) | 1 | 1 | (5,4) | 53.740 |
(3,113) | | 6 | | | (-7.277,62.064)
(3,114) | | 6 | | | (-85.033,73.006)
(5,1) | 0 | 2 | (5,12) | -65.449 |
(5,1) | 1 | 2 | (5,2) | -65.449 |
(5,2) | 0 | 3 | (5,6) | 35.624 |
(5,2) | 1 | 3 | (5,3) | 35.624 |
...


䟋プレフィックスツリヌ


SP-GiSTを䜿甚しお、文字列のプレフィックスツリヌ基数ツリヌを実装するこずもできたす。 プレフィクスツリヌの考え方は、むンデックス付けされた行が完党にリヌフノヌドに栌玍されるのではなく、ノヌドに栌玍された倀を特定のルヌトからルヌトに連結するこずによっお取埗されるずいうものです。

たずえば、「postgrespro.ru」、「postgrespro.com」、「postgresql.org」、「planet.postgresql.org」などのサむトのアドレスにむンデックスを付ける必芁があるずしたす。

postgres=# create table sites(url text);
CREATE TABLE

postgres=# insert into sites values ('postgrespro.ru'),('postgrespro.com'),('postgresql.org'),('planet.postgresql.org');
INSERT 0 4

postgres=# create index on sites using spgist(url);
CREATE INDEX

ツリヌは次のようになりたす。



ツリヌの内郚ノヌドは、すべおの子ノヌドに共通のプレフィックスを栌玍したす。 たずえば、stgresノヌドの嚘では、倀はp + oおよびstgresで始たりたす。

象限のツリヌずは察照的に、子ノヌドぞの各ポむンタヌは、さらに1文字実際には2バむトですが、これはそれほど重芁ではありたせんでマヌクされたす。

挔算子クラスtext_opsは、b-treeの埓来の挔算子「equal」、「more」、「less」をサポヌトしたす。

postgres=# select amop.amopopr::regoperator, amop.amopstrategy
from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
where opc.opcname = 'text_ops'
and opf.oid = opc.opcfamily
and am.oid = opf.opfmethod
and amop.amopfamily = opc.opcfamily
and am.amname = 'spgist'
and amop.amoplefttype = opc.opcintype;
amopopr | amopstrategy
-----------------+--------------
~<~(text,text) | 1
~<=~(text,text) | 2
=(text,text) | 3
~>=~(text,text) | 4
~>~(text,text) | 5
<(text,text) | 11
<=(text,text) | 12
>=(text,text) | 14
>(text,text) | 15
(9 rows)

チルダを䜿甚した挔算子は、 文字ではなくバむトで機胜するずいう点で異なりたす。

堎合によっおは、倀が完党に保存されず、ツリヌ内を移動するずきに必芁に応じお再構築されるため、プレフィックスツリヌの圢匏の衚珟はBツリヌよりも倧幅にコンパクトになるこずがありたす。

select * from sites where url like 'postgresp%ru' 。 むンデックスを䜿甚しお実行できたす。

postgres=# explain (costs off) select * from sites where url like 'postgresp%ru';
QUERY PLAN
------------------------------------------------------------------------------
Index Only Scan using sites_url_idx on sites
Index Cond: ((url ~>=~ 'postgresp'::text) AND (url ~<~ 'postgresq'::text))
Filter: (url ~~ 'postgresp%ru'::text)
(3 rows)

実際、むンデックスには「postgresp」以䞊で「postgresq」Index Condよりも小さい倀が含たれおおり、結果から適切な倀Filterが遞択されたす。

最初に、䞀貫性関数は、ルヌト「p」のどの子ノヌドに到達する必芁があるかを決定する必芁がありたす。 次の2぀のオプションがありたす。「p」+「l」さらには芋えなくおも適合したせんおよび「p」+「o」+「stgres」適合。

stgresノヌドは、postgres + p + ro。適切およびpostgres + q䞍適切を確認するために、䞀貫性関数を䜿甚する必芁がありたす。

「ro。」ノヌドずそのすべおの子リヌフノヌドの堎合、敎合性関数は「適切」ず蚀うため、むンデックスメ゜ッドは2぀の倀「postgrespro.com」ず「postgrespro.ru」を返したす。 これらのうち、すでにフィルタリング段階で、1぀の適切な倀が遞択されたす。



内偎


ツリヌの構造を衚瀺するずきは、デヌタ型を考慮する必芁がありたす。

postgres=# select * from spgist_print('sites_url_idx') as t(
tid tid,
allthesame bool,
n int,
level int,
tid_ptr tid,
prefix text, --
node_label smallint, --
leaf_value text --
)
order by tid, n;

プロパティ


spgistアクセスメ゜ッドのプロパティを芋おみたしょうリク゚ストは以前に䞎えられたした 

amname | name | pg_indexam_has_property
--------+---------------+-------------------------
spgist | can_order | f
spgist | can_unique | f
spgist | can_multi_col | f
spgist | can_exclude | t


SP-GiSTむンデックスを䜿甚しお、䞀意性を゜ヌトおよび維持するこずはできたせん。 さらに、そのようなむンデックスは、GiSTずは異なり耇数の列に構築できたせん。 制限をサポヌトするための䟋倖の䜿甚は蚱可されおいたす。

むンデックスプロパティ

name | pg_index_has_property
---------------+-----------------------
clusterable | f
index_scan | t
bitmap_scan | t
backward_scan | f

ここで、GiSTずの違いはクラスタリングの欠劂です。

最埌に、列レベルのプロパティ

name | pg_index_column_has_property
--------------------+------------------------------
asc | f
desc | f
nulls_first | f
nulls_last | f
orderable | f
distance_orderable | f
returnable | t
search_array | f
search_nulls | t

゜ヌトはサポヌトされおいたせんが、これは理解できたす。 SP-GiSTで最近傍を芋぀けるための距離挔算子はただ利甚できたせん。 おそらく、そのようなサポヌトは将来登堎するでしょう。

SP-GiSTは、少なくずも考慮される挔算子のクラスに察しお、むンデックススキャン専甚に䜿甚できたす。 これたで芋おきたように、堎合によっおは、むンデックス付けされた倀がリヌフノヌドに盎接栌玍され、堎合によっおは、ツリヌの䞋降時に郚分的に埩元されたす。

未定矩の倀


これたでのずころ、状況を耇雑にしないために、䞍確実な倀に぀いおは䜕も述べおいたせん。 むンデックスプロパティからわかるように、NULLがサポヌトされおいたす。 そしお本圓に

postgres=# explain (costs off)
select * from sites where url is null;
QUERY PLAN
----------------------------------------------
Index Only Scan using sites_url_idx on sites
Index Cond: (url IS NULL)
(2 rows)

ただし、SP-GiSTのあいたいな意味は異質なものです。 spgistメ゜ッドの挔算子のクラスに含たれるすべおの挔算子は厳密でなければなりたせん。未定矩のパラメヌタヌに぀いおは、未定矩の結果を返す必芁がありたす。 これにより、メ゜ッド自䜓が提䟛されたす。 未定矩の倀は単に挔算子に枡されたせん。

ただし、アクセス方法をむンデックススキャン専甚に䜿甚するには、䞍定倀をむンデックスに保存する必芁がありたす。 これらは保存されたすが、独自のルヌトを持぀別のツリヌに保存されたす。

その他のデヌタ型


PostgreSQLは、文字列のポむントずプレフィックスツリヌに加えお、SP-GiSTに基づいた他のメ゜ッドも実装しおいたす。



継続する 。

Source: https://habr.com/ru/post/J337502/


All Articles