PostgreSQLã®ã€ã³ããã¯ã¹äœæã¡ã«ããºã ãš
ã¢ã¯ã»ã¹æ¹æ³ã®
ã€ã³ã¿ãŒãã§ãŒã¹ã«ãã§ã«æ
£ããŠããã
ããã·ã¥ã€ã³ããã¯ã¹ ã
BããªãŒ ã
GiST ãããã³
SP-GiSTã€ã³ããã¯ã¹ã調ã¹ãŸããã ãã®éšåã§ã¯ãGINã€ã³ããã¯ã¹ãæ±ããŸãã
ãžã³
-ãžã³ïŒ..ãžã³-ãããªã¢ã¡ãªã«ã®é
ã®ããã«èŠããïŒ-ç§ã¯é£²ã¿ç©ã§ã¯ãããŸãã è人ã¯åã³é¡ãèµ€ãããåã³èªåãæãŸããåã³äžç·ã«åŒã£åŒµããŸããã -飲ã¿ç©ã§ã¯ãªãã匷åã§andç¶ãšãã粟ç¥ããããŠç§ãè²·ãäœè£ã®ãªããããªéæ³ã¯äžçã«ã¯ãããŸãããã©ã¶ãŒã©ã®ã³ããè人ãããã¿ããã
Ginã¯Generalized Inverted Indexã®ç¥ã§ã飲ã¿ç©ã§ã¯ãªã粟éãšèŠãªãããã¹ãã§ããReadmeäžè¬çãªèãæ¹
GINã¯Generalized Inverted Indexã®ç¥ã§ããããã¯ãããã
éã€ã³ããã¯ã¹ã§ãã å€ãã¢ãããã¯ã§ã¯ãªããèŠçŽ ã§æ§æãããããŒã¿åã§æ©èœããŸãã åæã«ãå€èªäœã«ã€ã³ããã¯ã¹ãä»ããããã®ã§ã¯ãªããåã
ã®èŠçŽ ã«ã€ã³ããã¯ã¹ãä»ããããŸãã åèŠçŽ ã¯ããããçºçããå€ãåç
§ããŸãã
ãã®æ¹æ³ã®è¯ãäŸãã¯ãæ¬ã®æåŸã®çŽ¢åŒã§ããåçšèªã«ã¯ããã®çšèªãèšèŒãããŠããããŒãžã®ãªã¹ãããããŸãã æ¬ã®ãã€ã³ã¿ãŒãšåæ§ã«ãindexã¡ãœããã¯ã€ã³ããã¯ã¹ä»ãã¢ã€ãã ã®ã¯ã€ãã¯æ€çŽ¢ãæäŸããå¿
èŠããããŸãã ãããè¡ãããã«ããããã¯ãã§ã«éŠŽæã¿ã®ãã
BããªãŒã®åœ¢åŒã§ä¿åãã
ãŸã ïŒå¥ã®ããåçŽãªå®è£
ã䜿çšãããŸããããã®å Žåã¯å¿
é ã§ã¯ãããŸããïŒã åèŠçŽ ã¯ããã®èŠçŽ ã®å€ãå«ãããŒãã«è¡ãžã®ãªã³ã¯ã®é åºä»ãã»ããã«ãã£ãŠãã€ã³ããããŸãã ããŒã¿ãµã³ããªã³ã°ã§ã¯é åºä»ãã¯éèŠã§ã¯ãããŸããïŒTIDã®äžŠã¹æ¿ãé åºã¯ããŸãæå³ããããŸããïŒããã€ã³ããã¯ã¹ã®å
éšæ§é ã®èŠ³ç¹ããã¯éèŠã§ãã
GINã€ã³ããã¯ã¹ããã¢ã€ãã ãåé€ãããããšã¯ãããŸããã èŠçŽ ãå«ãå€ã¯æ¶ããããåºçŸããããå€åãããããå¯èœæ§ããããšèããããŠããŸãããèŠçŽ ãæ§æããèŠçŽ ã®ã»ããã¯éåžžã«éçã§ãã ãã®ãœãªã¥ãŒã·ã§ã³ã¯ãè€æ°ã®ããã»ã¹ã®ã€ã³ããã¯ã¹ã䜿çšããŠäžŠåæäœãæäŸããã¢ã«ãŽãªãºã ã倧å¹
ã«ç°¡çŽ åããŸãã
TIDã®ãªã¹ããååã«å°ããå Žåã¯ãã¢ã€ãã ãšåãããŒãžã«é
眮ãããŸãïŒæçš¿ãªã¹ããšåŒã°ããŸãïŒã ãã ãããªã¹ãã倧ããå Žåã¯ãããå¹ççãªããŒã¿æ§é ãå¿
èŠã§ãããæ¢ã«ããã£ãŠããŸã-ãããBããªãŒã§ãã ãã®ãããªããªãŒã¯ãåå¥ã®ããŒã¿ããŒãžã«é
眮ãããŸãïŒæçš¿ããªãŒãšåŒã°ããŸãïŒã
ãããã£ãŠãGINã€ã³ããã¯ã¹ã¯ãBããªãŒãŸãã¯TIDã®ãã©ãããªã¹ããæ·»ä»ãããŠãããªãŒãã¬ã³ãŒãã«ãèŠçŽ ã®BããªãŒã§æ§æãããŸãã
åè¿°ã®GiSTããã³SP-GiSTã€ã³ããã¯ã¹ãšåæ§ã«ãGINã¯ãè€éãªããŒã¿åã«å¯ŸããããŸããŸãªæäœããµããŒãããã€ã³ã¿ãŒãã§ã€ã¹ãã¢ããªã±ãŒã·ã§ã³éçºè
ã«æäŸããŸãã
å
šææ€çŽ¢
ginã¡ãœããã®äž»ãªé©çšåéã¯å
šææ€çŽ¢ã®é«éåã§ãããã®äŸã§ã¯ããã®ã€ã³ããã¯ã¹ããã詳现ã«æ€èšããããšãè«ççã§ãã
GiSTã«ã€ããŠã¯ãå
šææ€çŽ¢ã®
ç°¡åãªçŽ¹ä»ãæ¢ã«ãããŸããã®ã§ããããç¹°ãè¿ããŠèŠç¹ã説æããŸããã ãã®å Žåã®è€éãªå€ã¯
ããã¥ã¡ã³ãã§ããããããã®ããã¥ã¡ã³ãã®èŠçŽ ã¯
ããŒã¯ã³ã§ããããšã¯æããã§ã
ãGiSTã«é¢ããéšåã§æ€èšããã®ãšåãäŸãåãäžããŸãïŒãªãã¬ã€ã³ã2åç¹°ãè¿ããŸãïŒã
postgres=# create table ts(doc text, doc_tsv tsvector);
CREATE TABLE
postgres=# insert into ts(doc) values
(' '), (' '),
(', , '), (', , '),
(' '), (' '),
(', , '), (', , '),
(' '), (' '),
(', , '), (', , ');
INSERT 0 12
postgres=# set default_text_search_config = russian;
SET
postgres=# update ts set doc_tsv = to_tsvector(doc);
UPDATE 12
postgres=# create index on ts using gin(doc_tsv);
CREATE INDEX
ãã®ãããªã€ã³ããã¯ã¹ã®å¯èœãªæ§é ãå³ã«ç€ºããŸãã

åã®ãã¹ãŠã®å³ãšã¯ç°ãªããããŒãã«è¡ïŒTIDïŒãžã®ãªã³ã¯ã¯ç¢å°ã§ã¯ãªããæãèæ¯ã®æ°å€ïŒããŒãžçªå·ãšããŒãžå
ã®äœçœ®ïŒã§è¡šç€ºãããŸãã
postgres=# select ctid, doc, doc_tsv from ts;
ctid | doc | doc_tsv
--------+-------------------------+--------------------------------
(0,1) | | '':3 '':2 '':4
(0,2) | | '':3 '':2 '':4
(0,3) | , , | '':1,2 '':3
(0,4) | , , | '':1,2 '':3
(1,1) | | '':2 '':3 '':1
(1,2) | | '':3 '':2 '':1
(1,3) | , , | '':3 '':1,2
(1,4) | , , | '':3 '':1,2
(2,1) | | '':3 '':2
(2,2) | | '':1 '':2 '':3
(2,3) | , , | '':3 '':1,2
(2,4) | , , | '':3 '':1,2
(12 rows)
ææ©çãªäŸã§ã¯ãTIDã®ãªã¹ãã¯ããlyulããé€ããã¹ãŠã®ããŒã¯ã³ã®éåžžã®ããŒãžã«åãŸããŸãã ãã®ããŒã¯ã³ã¯æ倧6ã€ã®ããã¥ã¡ã³ãã§æ€åºãããTIDã®ãªã¹ãã¯å¥ã®BããªãŒã«é
眮ãããŸããã
ãšããã§ãããŒã¯ã³ãå«ãããã¥ã¡ã³ãã®æ°ãã©ã®ããã«ç解ããã®ã§ããïŒ ä»¥äžã«ç€ºãããã«ãå°ããªããŒãã«ã®å ŽåããçŽæ¥ãã¡ãœãããæ©èœããŸãããŸãã倧ããªããŒãã«ã®å Žåã¯åŸã§èª¬æããŸãã
postgres=# select (unnest(doc_tsv)).lexeme, count(*) from ts group by 1 order by 2 desc;
lexeme | count
---------+-------
| 6
| 4
| 4
| 3
| 3
| 2
| 2
| 2
| 1
| 1
| 1
(11 rows)
ãŸããéåžžã®BããªãŒãšã¯ç°ãªããGINã€ã³ããã¯ã¹ããŒãžã¯åæ¹åã§ã¯ãªãåæ¹åãªã¹ãã«ãã£ãŠãªã³ã¯ãããŠããããšã«æ³šæããŠãã ããã ããªãŒãã©ããŒãµã«ã¯åžžã«äžæ¹åã«ã®ã¿å®è¡ããããããããã§ååã§ãã
ãªã¯ãšã¹ãäŸ
ãã®äŸã§ã¯ã次ã®ã¯ãšãªã¯ã©ã®ããã«å®è¡ãããŸããïŒ
postgres=# explain(costs off)
select doc from ts where doc_tsv @@ to_tsquery(' & ');
QUERY PLAN
------------------------------------------------------------------------
Bitmap Heap Scan on ts
Recheck Cond: (doc_tsv @@ to_tsquery(' & '::text))
-> Bitmap Index Scan on ts_doc_tsv_idx
Index Cond: (doc_tsv @@ to_tsquery(' & '::text))
(4 rows)
æåã«ãæ€çŽ¢ã¯ãšãªããç¬ç«ããããŒã¯ã³ïŒæ€çŽ¢ããŒïŒãéžæãããŸãïŒã¹ã¿ã³ãã£ã³ã°ãšã«ãŒãªãŒã ããã¯ãæŒç®åã¯ã©ã¹ã§å®çŸ©ãããããŒã¿åãšæŠç¥ãèæ
®ããç¹å¥ãªAPIé¢æ°ã«ãã£ãŠè¡ãããŸãã
postgres=# select amop.amopopr::regoperator, amop.amopstrategy
from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
where opc.opcname = 'tsvector_ops'
and opf.oid = opc.opcfamily
and am.oid = opf.opfmethod
and amop.amopfamily = opc.opcfamily
and am.amname = 'gin'
and amop.amoplefttype = opc.opcintype;
amopopr | amopstrategy
-----------------------+--------------
@@(tsvector,tsquery) | 1
@@@(tsvector,tsquery) | 2 @@ ( )
(2 rows)
次ã«ãããŒã¯ã³ã®BããªãŒã§äž¡æ¹ã®ããŒãèŠã€ããTIDã®æºåå®äºãªã¹ããå埩åŠçããŸãã ååŸãããã®ïŒ
- ãç«ã£ãŠãããå Žå-ïŒ0.1ïŒãïŒ0.2ïŒãïŒ0.3ïŒãïŒ0.4ïŒ;
- ãã«ãŒã«ãã®å Žå-ïŒ0.2ïŒãïŒ1.2ïŒã

æåŸã«ãèŠã€ãã£ãTIDããšã«ãäžèŽããAPIé¢æ°ãåŒã³åºãããŸããããã«ãããæ€çŽ¢ãããè¡ã®ã©ããæ€çŽ¢ã¯ãšãªã«é©ããŠããããå€æãããŸãã ã¯ãšãªããŒã¯ã³ã§ã¯è«ççãªãandãã§çµåãããŠããããã1è¡ãè¿ãããŸãïŒ0,2ïŒïŒ
| | |
| | |
TID | | | &
-------+------+--------+-----------------
(0,1) | T | f | f
(0,2) | T | T | T
(0,3) | T | f | f
(0,4) | T | f | f
(1,2) | f | T | f
ãããŠãçµæãåŸãããŸãã
postgres=# select doc from ts where doc_tsv @@ to_tsquery(' & ');
doc
-------------------------
(1 row)
ãã®ã¢ãããŒããGiSTã«é¢ããŠæ€èšããã¢ãããŒããšæ¯èŒãããšãå
šææ€çŽ¢ã«å¯ŸããGINã®å©ç¹ã¯æããã§ãã ããããããã»ã©åçŽã§ã¯ãããŸããã
é
ãæŽæ°ã®åé¡
å®éãGINã€ã³ããã¯ã¹ã§ã®ããŒã¿ã®æ¿å
¥ãŸãã¯æŽæ°ã¯æ¯èŒçé
ãã§ãã éåžžãåããã¥ã¡ã³ãã«ã¯ãã€ã³ããã¯ã¹ä»ããããããŒã¯ã³ãå€æ°å«ãŸããŠããŸãã ãããã£ãŠã1ã€ã®ããã¥ã¡ã³ãã衚瀺ãŸãã¯å€æŽããããšãã€ã³ããã¯ã¹ããªãŒã«å€§å¹
ãªå€æŽãå ããå¿
èŠããããŸãã
äžæ¹ãè€æ°ã®ããã¥ã¡ã³ããäžåºŠã«å€æŽããããšãäžéšã®ããŒã¯ã³ãäžèŽããå Žåããããããã¥ã¡ã³ãã1ã€ãã€å€æŽããå Žåãããç·äœæ¥éãå°ãªããªããŸãã
GINã€ã³ããã¯ã¹ã«ã¯ãã€ã³ããã¯ã¹ã®äœææã«æå®ããããåŸã§å€æŽãããã§ããfastupdateã¹ãã¬ãŒãžãã©ã¡ãŒã¿ããããŸãã
postgres=# create index on ts using gin(doc_tsv) with (fastupdate = true);
CREATE INDEX
ãã®ãªãã·ã§ã³ãæå¹ã«ãããšãå€æŽã¯ãåå¥ã®é åºä»ããããŠããªããªã¹ãã®åœ¢åŒã§ïŒåå¥ã®ãªã³ã¯ããŒãžã«ïŒèç©ãããŸãã ãã®ãªã¹ããååã«å€§ãããªãããã¯ãªãŒãã³ã°ããã»ã¹äžã«ã环ç©ããããã¹ãŠã®å€æŽãããã«ã€ã³ããã¯ã¹ã«å ããããŸãã ãååã«å€§ããããªã¹ããšèŠãªããããã®ã¯ãgin_pending_list_limitæ§æãã©ã¡ãŒã¿ãŒãŸãã¯åãååã®ã€ã³ããã¯ã¹ã¹ãã¬ãŒãžãã©ã¡ãŒã¿ãŒã«ãã£ãŠæ±ºå®ãããŸãã
ãããããã®ã¢ãããŒãã«ã¯ãã€ãã¹é¢ããããŸãïŒãŸããæ€çŽ¢ãé
ããªããŸãïŒããªãŒã«å ããŠãé åºä»ããããŠããªããªã¹ãã確èªããå¿
èŠãããããïŒã次ã«ãé åºä»ããããŠããªããªã¹ãããã£ã±ãã«ãªããšã次ã®å€æŽã«çªç¶æéããããããšããããŸãã
éšåäžèŽæ€çŽ¢
å
šææ€çŽ¢ã§ã¯ãéšåäžèŽã䜿çšã§ããŸãã ãªã¯ãšã¹ãã¯ãããšãã°æ¬¡ã®ããã«å®åŒåãããŸãã
gin=# select doc from ts where doc_tsv @@ to_tsquery(':*');
doc
-------------------------
, ,
, ,
, ,
, ,
(7 rows)
ãã®ãããªã¯ãšãªã¯ããããŒã«ãã§å§ãŸãããŒã¯ã³ãå«ãããã¥ã¡ã³ããæ€çŽ¢ããŸãã ã€ãŸãããã®äŸã§ã¯ããæãç®ãïŒãbreakããšããåèªããååŸïŒãšãæãç®ãïŒãcreaseããšããåèªããïŒã§ãã
ãã¡ãããã¯ãšãªã¯ã€ã³ããã¯ã¹ããªããŠãåäœããŸãããGINã䜿çšãããšãã®æ€çŽ¢ãé«éåã§ããŸãã
postgres=# explain (costs off)
select doc from ts where doc_tsv @@ to_tsquery(':*');
QUERY PLAN
--------------------------------------------------------------
Bitmap Heap Scan on ts
Recheck Cond: (doc_tsv @@ to_tsquery(':*'::text))
-> Bitmap Index Scan on ts_doc_tsv_idx
Index Cond: (doc_tsv @@ to_tsquery(':*'::text))
(4 rows)
ãã®å Žåãæ€çŽ¢ã¯ãšãªã§æå®ããããã¬ãã£ãã¯ã¹ãæã€ãã¹ãŠã®ããŒã¯ã³ã¯ãããŒã¯ã³ããªãŒã«é
眮ãããè«çãorãã«ãã£ãŠçµåãããŸãã
é »ç¹ãã€ãŸããªããŒã¯ã³
å®éã®ããŒã¿ã§ã€ã³ããã¯ã¹äœæãã©ã®ããã«æ©èœãããã確èªããã«ã¯ãGiSTã¹ã¬ããã§æ¢ã«äœ¿çšããpgsql-hackersã¡ãŒãªã³ã°ãªã¹ãã¢ãŒã«ã€ããå©çšããŸãã
ãã®ã¢ãŒã«ã€ãããŒãžã§ã³ã«ã¯ãåºçºæ¥ã件åãèè
ãããã³ããã¹ããå«ã356125æåãå«ãŸããŠããŸãã
fts=# alter table mail_messages add column tsv tsvector;
ALTER TABLE
fts=# set default_text_search_config = default;
SET
fts=# update mail_messages
set tsv = to_tsvector(body_plain);
NOTICE: word is too long to be indexed
DETAIL: Words longer than 2047 characters are ignored.
...
UPDATE 356125
fts=# create index on mail_messages using gin(tsv);
CREATE INDEX
å€æ°ã®ããã¥ã¡ã³ãã§èŠã€ãã£ãããŒã¯ã³ãååŸããŸãã unnestã䜿çšããã¯ãšãªã¯ããã®ãããªããŒã¿éã§ã¯æ©èœããªããªããŸããæ£ããæ¹æ³ã¯ãããŒã¯ã³ã«é¢ããæ
å ±ãããããçºçããããã¥ã¡ã³ãã®æ°ãããã³ãšã³ããªã®ç·æ°ã衚瀺ããts_staté¢æ°ã䜿çšããããšã§ãã
fts=# select word, ndoc
from ts_stat('select tsv from mail_messages')
order by ndoc desc limit 3;
word | ndoc
-------+--------
re | 322141
wrote | 231174
use | 176917
(3 rows)
ãæžã蟌ã¿ããéžæããŸãã
ãŸããéçºè
ã®ã¡ãŒãªã³ã°ãªã¹ãã§ãã¿ãã¥ãŒããªã©ã®ãŸããªèšèãåãäžããŸãã
fts=# select word, ndoc from ts_stat('select tsv from mail_messages') where word = 'tattoo';
word | ndoc
--------+------
tattoo | 2
(1 row)
ãããã®ããŒã¯ã³ãåæã«çºçããããã¥ã¡ã³ãã¯ãããŸããïŒ ããã¯æ¬¡ã®ãšããã§ãã
fts=# select count(*) from mail_messages where tsv @@ to_tsquery('wrote & tattoo');
count
-------
1
(1 row)
åé¡ã¯ããã®èŠæ±ãæºããæ¹æ³ã§ãã äžèšã®ããã«ãäž¡æ¹ã®ããŒã¯ã³ã®TIDã®ãªã¹ããåãåã£ãå Žåãæ€çŽ¢ã¯æããã«éå¹ççã§ãã20äžãè¶
ããå€ãæŽçããå¿
èŠããããçµæãšããŠ1ã€ã ããæ®ããŸãã 幞ããªããšã«ããã©ã³ããŒã®çµ±èšã䜿çšããŠãã¢ã«ãŽãªãºã ã¯ãããŒã¯ã³ãããŒã¯ã³ãäžè¬çã§ããããã¿ãã¥ãŒãããŸãã§ããããšãç解ããŸãã ãããã£ãŠãæ€çŽ¢ã¯ãŸããªããŒã¯ã³ã䜿çšããŠå®è¡ãããçµæã®2ã€ã®ããã¥ã¡ã³ãã§ãæžã蟌ãŸãããããŒã¯ã³ã®ååšã確èªãããŸãã ã芧ã®ãšããããªã¯ãšã¹ãã¯è¿
éã«å®è¡ãããŸãã
fts=# \timing on
Timing is on.
fts=# select count(*) from mail_messages where tsv @@ to_tsquery('wrote & tattoo');
count
-------
1
(1 row)
Time: 0,959 ms
æ€çŽ¢ã¯åã«ãæžãããããã¯ããã«é·ãïŒ
fts=# select count(*) from mail_messages where tsv @@ to_tsquery('wrote');
count
--------
231174
(1 row)
Time: 2875,543 ms (00:02,876)
ãã¡ããããã®ãããªæé©åã¯ã2ã€ã®ããŒã¯ã³ã ãã§ãªããããè€éãªã±ãŒã¹ã§ãæ©èœããŸãã
ãµã³ããªã³ã°å¶é
ginã¢ã¯ã»ã¹ã¡ãœããã®ç¹åŸŽã¯ãçµæãåžžã«
ããããããã®åœ¢åŒã§è¿ãããããšã§ã
ããã®ã¡ãœããã¯ãäžåºŠã«1ã€ãã€TIDãçºè¡ããããšã¯ã§ããŸããã ãã®ããããã®éšåã§çºçãããã¹ãŠã®ã¯ãšãªãã©ã³ã§ããããããã¹ãã£ã³ã䜿çšãããŸãã
ãã®ãããLIMITå¥ã䜿çšããŠã€ã³ããã¯ã¹ã§éžæãå¶éããããšã¯ããŸãå¹æçã§ã¯ãããŸããã æäœã®äºæž¬ã³ã¹ãïŒå¶éããŒãã®ãã³ã¹ãããã£ãŒã«ãïŒã«æ³šæããŠãã ããã
fts=# explain (costs off)
select * from mail_messages where tsv @@ to_tsquery('wrote') limit 1;
QUERY PLAN
-----------------------------------------------------------------------------------------
Limit (cost=1283.61..1285.13 rows=1)
-> Bitmap Heap Scan on mail_messages (cost=1283.61..209975.49 rows=137207)
Recheck Cond: (tsv @@ to_tsquery('wrote'::text))
-> Bitmap Index Scan on mail_messages_tsv_idx (cost=0.00..1249.30 rows=137207)
Index Cond: (tsv @@ to_tsquery('wrote'::text))
(5 rows)
ã³ã¹ãã¯1283.61ãšæšå®ããããããããã1249.30å
šäœãæ§ç¯ããã³ã¹ãïŒããããããã€ã³ããã¯ã¹ã¹ãã£ã³ããŒãã®ãã³ã¹ãããã£ãŒã«ãïŒãããããã«é«ããªããŸãã
ãããã£ãŠãã€ã³ããã¯ã¹ã«ã¯çµæã®æ°ãå¶éããç¹å¥ãªæ©èœããããŸãã ãããå€ã¯ãæ§æãã©ã¡ãŒã¿ãŒgin_fuzzy_search_limitã§èšå®ãããããã©ã«ãã§ã¯ãŒãã«ãªããŸãïŒå¶éã¯çºçããŸããïŒã ãã ããã€ã³ã¹ããŒã«ããããšã¯ã§ããŸãã
fts=# set gin_fuzzy_search_limit = 1000;
SET
fts=# select count(*) from mail_messages where tsv @@ to_tsquery('wrote');
count
-------
5746
(1 row)
fts=# set gin_fuzzy_search_limit = 10000;
SET
fts=# select count(*) from mail_messages where tsv @@ to_tsquery('wrote');
count
-------
14726
(1 row)
ã芧ã®ãšãããã¯ãšãªã¯ç°ãªããã©ã¡ãŒã¿å€ã«å¯ŸããŠç°ãªãè¡æ°ãè¿ããŸãïŒã€ã³ããã¯ã¹ã¢ã¯ã»ã¹ã䜿çšãããŠããå ŽåïŒã å¶éã¯å³å¯ã§ã¯ãããŸããã æå®ãããè¡ããå€ãã®è¡ãè¿ãããå¯èœæ§ãããããããã¡ãžãŒã§ãã
ã³ã³ãã¯ããªããã©ãŒãã³ã¹
ãšããããGINã€ã³ããã¯ã¹ã¯ã³ã³ãã¯ãæ§ã«åªããŠããŸãã æåã«ãåãããŒã¯ã³ãè€æ°ã®ããã¥ã¡ã³ãã§èŠã€ãã£ãå ŽåïŒéåžžãããçºçããŸãïŒãã€ã³ããã¯ã¹ã«1åã ãæ ŒçŽãããŸãã 第äºã«ãTIDã¯èŠåçã«ã€ã³ããã¯ã¹ã«æ ŒçŽãããããã«ããåçŽãªå§çž®ã䜿çšããããšãã§ããŸãïŒãªã¹ãå
ã®æ¬¡ã®åTIDã¯å®éã«ã¯åã®ãã®ãšã®å·®åãšããŠæ ŒçŽãããŸã-éåžžãããã¯å®å
šãª6ãããã¯ããã«å°ãªããããã§æžã¿ãŸããã€ãTIDã
ããªã¥ãŒã ã®ã¢ã€ãã¢ãåŸãã«ã¯ãæåã®ããã¹ãããBããªãŒãäœæããŸãã ãã¡ãããæ£çŽãªæ¯èŒã¯æ©èœããŸããã
- GINã¯ç°ãªãããŒã¿åïŒããã¹ãã§ã¯ãªãtsvectorïŒã«åºã¥ããŠæ§ç¯ãããŠãããããå°ããã
- ãã ããBããªãŒã®æåã®ãµã€ãºã¯çŽ2ãããã€ãã«ççž®ããå¿
èŠããããŸãã
ããããããã§ãïŒ
fts=# create index mail_messages_btree on mail_messages(substring(body_plain for 2048));
CREATE INDEX
åæã«ãGiSTã€ã³ããã¯ã¹ãäœæããŸãã
fts=# create index mail_messages_gist on mail_messages using gist(tsv);
CREATE INDEX
ãã«ã¯ãªãŒãã³ã°åŸã®ã€ã³ããã¯ã¹ãµã€ãºïŒããã¥ãŒã ãã«ïŒïŒ
fts=# select pg_size_pretty(pg_relation_size('mail_messages_tsv_idx')) as gin,
pg_size_pretty(pg_relation_size('mail_messages_gist')) as gist,
pg_size_pretty(pg_relation_size('mail_messages_btree')) as btree;
gin | gist | btree
--------+--------+--------
179 MB | 125 MB | 546 MB
(1 row)
ãã¬ãŒã³ããŒã·ã§ã³ãã³ã³ãã¯ãã§ãããããOracleããããããããã€ã³ããã¯ã¹ã®ä»£ãããšããŠç§»è¡ãããšãã«GINã€ã³ããã¯ã¹ã䜿çšããããšãã§ããŸãïŒè©³çŽ°ã«ã¯è§ŠããŸãããã奜å¥å¿mindçãªäººã®
ããã«ãã«ã€ã¹ãã¹ããžã®ãªã³ã¯ãæ®ããŸãïŒã éåžžãããããããã€ã³ããã¯ã¹ã¯ããããã«äžæã®å€ãæã€ãã£ãŒã«ãã«äœ¿çšãããŸã-ããã¯GINã«é©ããŠããŸãã PostgreSQLã¯
ãæåã®ããŒãã§èŠããã
ã«ã GINãå«ãä»»æã®ã€ã³ããã¯ã¹ã«åºã¥ããŠãã®å Žã§ãããããããæ§ç¯ã§ããŸãã
GiSTãŸãã¯GINïŒ
å€ãã®ããŒã¿åã«ã¯ãGiSTãšGINã®äž¡æ¹ã®æŒç®åã¯ã©ã¹ããããçåãæèµ·ããŸããäœã䜿çšããã®ã§ããïŒ ãããããããã€ãã®çµè«ãåŒãåºãããšã¯ãã§ã«å¯èœã§ãã
ååãšããŠãGINã¯ç²ŸåºŠãšé床ã«ãããŠGiSTãããåªããŠããŸãã ããŒã¿ãé »ç¹ã«å€æŽãããªãããããã«æ€çŽ¢ããå¿
èŠãããå Žå-ã»ãšãã©ã®å Žåãéžæã¯GINã«åœãŠã¯ãŸããŸãã
äžæ¹ãããŒã¿ãã¢ã¯ãã£ãã«å€æŽãããå ŽåãGINãæŽæ°ãããªãŒããŒãããã倧ããããå¯èœæ§ããããŸãã ãã®å Žåãäž¡æ¹ã®ãªãã·ã§ã³ãæ¯èŒããã€ã³ãžã±ãŒã¿ãŒã®ãã©ã³ã¹ãããè¯ããªãã·ã§ã³ãéžæããå¿
èŠããããŸãã
é
å
ginã¡ãœããã䜿çšããå¥ã®äŸã¯ãé
åã®ã€ã³ããã¯ã¹ä»ãã§ãã ãã®å Žåãé
åã®èŠçŽ ã¯ã€ã³ããã¯ã¹ã«åé¡ãããããããããã®èŠçŽ ã«å¯Ÿããå€ãã®æäœãé«éåã§ããŸãã
postgres=# select amop.amopopr::regoperator, amop.amopstrategy
from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
where opc.opcname = 'array_ops'
and opf.oid = opc.opcfamily
and am.oid = opf.opfmethod
and amop.amopfamily = opc.opcfamily
and am.amname = 'gin'
and amop.amoplefttype = opc.opcintype;
amopopr | amopstrategy
-----------------------+--------------
&&(anyarray,anyarray) | 1
@>(anyarray,anyarray) | 2
<@(anyarray,anyarray) | 3
=(anyarray,anyarray) | 4
(4 rows)
ãã¢ããŒã¿ããŒã¹ã«ã¯ããã©ã€ãæ
å ±ãå«ãã«ãŒããã¥ãŒããããŸãã ç¹ã«ãdays_of_weekåïŒãã©ã€ããè¡ãããææ¥ã®é
åïŒãå«ãŸããŠããŸãã ããšãã°ãVnukovoããGelendzhikãžã®ãã©ã€ãã¯ç«ææ¥ãæšææ¥ãæ¥ææ¥ã«åºçºããŸãã
demo=# select departure_airport_name, arrival_airport_name, days_of_week
from routes
where flight_no = 'PG0049';
departure_airport_name | arrival_airport_name | days_of_week
------------------------+----------------------+--------------
| | {2,4,7}
(1 row)
ã€ã³ããã¯ã¹ãäœæããã«ã¯ããã¥ãŒãããŒãã«ã«ããããªã¢ã©ã€ãºãããŸãã
demo=# create table routes_t as select * from routes;
SELECT 710
demo=# create index on routes_t using gin(days_of_week);
CREATE INDEX
ã€ã³ããã¯ã¹ã®å©ããåããŠãç«ææ¥ãæšææ¥ãæ¥ææ¥ã«åºçºãããã¹ãŠã®ãã©ã€ããèŠã€ããããšãã§ããŸãã
demo=# explain (costs off) select * from routes_t where days_of_week = ARRAY[2,4,7];
QUERY PLAN
-----------------------------------------------------------
Bitmap Heap Scan on routes_t
Recheck Cond: (days_of_week = '{2,4,7}'::integer[])
-> Bitmap Index Scan on routes_t_days_of_week_idx
Index Cond: (days_of_week = '{2,4,7}'::integer[])
(4 rows)
ãã®ãã¡ã®6ã€ãå€æããŠããŸãã
demo=# select flight_no, departure_airport_name, arrival_airport_name, days_of_week from routes_t where days_of_week = ARRAY[2,4,7];
flight_no | departure_airport_name | arrival_airport_name | days_of_week
-----------+------------------------+----------------------+--------------
PG0005 | | | {2,4,7}
PG0049 | | | {2,4,7}
PG0113 | - | | {2,4,7}
PG0249 | | | {2,4,7}
PG0449 | | | {2,4,7}
PG0540 | | | {2,4,7}
(6 rows)
ãã®ãããªãªã¯ãšã¹ãã¯ã©ã®ããã«å®è¡ãããŸããïŒ äžèšãšãŸã£ããåãæ¹æ³ã§ïŒ
- é
å{2,4,7}ããã®åœ¹å²ãæãããŠããæ€çŽ¢ã¯ãšãªãããèŠçŽ ïŒæ€çŽ¢ããŒïŒã匷調衚瀺ãããŸãã æããã«ããããã¯ã2ããã4ããã7ããšããå€ã«ãªããŸãã
- éžæãããããŒã¯èŠçŽ ããªãŒã«é
眮ãããããããã«å¯ŸããŠTIDã®ãªã¹ããéžæãããŸãã
- èŠã€ãã£ããã¹ãŠã®TIDã®ãã¡ãæŽåæ§æ©èœã¯ãèŠæ±ãããªãã¬ãŒã¿ãŒã«é©åãããã®ãéžæããŸãã æŒç®å=ã®å Žåã3ã€ã®ãªã¹ããã¹ãŠã«ããTIDã®ã¿ãé©åã§ãïŒã€ãŸãããœãŒã¹é
åã«ã¯ãã¹ãŠã®èŠçŽ ãå«ãŸããŠããå¿
èŠããããŸãïŒã ããããããã§ã¯ååã§ã¯ãããŸãããä»ã®å€ãå«ãŸãªãé
åãå¿
èŠã§ãããŸããã€ã³ããã¯ã¹ã§ãã®æ¡ä»¶ã確èªããããšã¯ã§ããŸããã ãããã£ãŠããã®å Žåãã¢ã¯ã»ã¹æ¹æ³ã¯ãããŒãã«ã«åŸã£ãŠçºè¡ããããã¹ãŠã®TIDãäºéãã§ãã¯ããããã«ã€ã³ããã¯ã¹äœæã¡ã«ããºã ã«èŠæ±ããŸãã
ãŸã£ããäœããã§ãã¯ã§ãããããŒãã«ããèŠã€ãã£ããã¹ãŠã®TIDãäºéãã§ãã¯ããããšãäœåãªããããæŠç¥ïŒããšãã°ããé
åã«å«ãŸãããïŒãããããšã¯èå³æ·±ãããšã§ãã
ããããç«ææ¥ãæšææ¥ãæ¥ææ¥ã«ã¢ã¹ã¯ã¯ããåºçºãããã©ã€ããç¥ãå¿
èŠãããå Žåã¯ã©ãã§ããããïŒ è¿œå ã®æ¡ä»¶ã¯ã€ã³ããã¯ã¹ã«ãã£ãŠãµããŒããããããã£ã«ã¿ãŒåã«åé¡ãããŸãã
demo=# explain (costs off)
select * from routes_t where days_of_week = ARRAY[2,4,7] and departure_city = '';
QUERY PLAN
-----------------------------------------------------------
Bitmap Heap Scan on routes_t
Recheck Cond: (days_of_week = '{2,4,7}'::integer[])
Filter: (departure_city = ''::text)
-> Bitmap Index Scan on routes_t_days_of_week_idx
Index Cond: (days_of_week = '{2,4,7}'::integer[])
(5 rows)
ãã®å Žåãããã¯æãããããšã§ã¯ãããŸããïŒã€ã³ããã¯ã¹ã¯ãã§ã«6è¡ã®ã¿ãéžæããŠããŸãïŒããè¿œå ã®æ¡ä»¶ãéžææ§ãé«ããå Žåããã®ãããªæ©äŒã欲ããã§ãã 確ãã«ãã€ã³ããã¯ã¹ãäœæããã ãã§ã¯æ©èœããŸããã
demo=# create index on routes_t using gin(days_of_week,departure_city);
ERROR: data type text has no default operator class for access method "gin"
HINT: You must specify an operator class for the index or define a default operator class for the data type.
ãã ããéåžžã®BããªãŒã®åäœãæš¡å£ããGINæŒç®åã®ã¯ã©ã¹ãè¿œå ãã
btree_ginæ¡åŒµæ©èœã圹ç«ã¡ãŸãã
demo=# create extension btree_gin;
CREATE EXTENSION
demo=# create index on routes_t using gin(days_of_week,departure_city);
CREATE INDEX
demo=# explain (costs off)
select * from routes_t where days_of_week = ARRAY[2,4,7] and departure_city = '';
QUERY PLAN
---------------------------------------------------------------------
Bitmap Heap Scan on routes_t
Recheck Cond: ((days_of_week = '{2,4,7}'::integer[]) AND
(departure_city = ''::text))
-> Bitmap Index Scan on routes_t_days_of_week_departure_city_idx
Index Cond: ((days_of_week = '{2,4,7}'::integer[]) AND
(departure_city = ''::text))
(4 rows)
ãžã§ã³ã
çµã¿èŸŒã¿ã®GINãµããŒããããè€éãªããŒã¿åã®ãã1ã€ã®äŸã¯JSONã§ãã JSONå€ãæäœããããã«ãçŸåšããã€ãã®æŒç®åãšé¢æ°ãå®çŸ©ãããŠããŸããããã®äžéšã¯ã€ã³ããã¯ã¹ã䜿çšããŠé«éåã§ããŸãã
postgres=# select opc.opcname, amop.amopopr::regoperator, amop.amopstrategy as str
from pg_opclass opc, pg_opfamily opf, pg_am am, pg_amop amop
where opc.opcname in ('jsonb_ops','jsonb_path_ops')
and opf.oid = opc.opcfamily
and am.oid = opf.opfmethod
and amop.amopfamily = opc.opcfamily
and am.amname = 'gin'
and amop.amoplefttype = opc.opcintype;
opcname | amopopr | str
----------------+------------------+-----
jsonb_ops | ?(jsonb,text) | 9
jsonb_ops | ?|(jsonb,text[]) | 10 -
jsonb_ops | ?&(jsonb,text[]) | 11
jsonb_ops | @>(jsonb,jsonb) | 7 JSON-
jsonb_path_ops | @>(jsonb,jsonb) | 7
(5 rows)
æããã«ãjsonb_opsãšjsonb_path_opsã®2ã€ã®ã¯ã©ã¹ã®æŒç®åããããŸãã
ããã©ã«ãã§ã¯ãæŒç®åã®æåã®ã¯ã©ã¹jsonb_opsã䜿çšãããŸãã é
åã®ãã¹ãŠã®ããŒãå€ãããã³èŠçŽ ã¯ãå
ã®JSONããã¥ã¡ã³ãã®èŠçŽ ãšããŠã€ã³ããã¯ã¹ã«åé¡ãããŸãã ãã®èŠçŽ ãããŒã§ãããã©ããã«ããããããããããã«èšå·ãè¿œå ãããŸãïŒããã¯ãããŒãšå€ãåºå¥ãããæ¢åã®ãæŠç¥ã«å¿
èŠã§ãïŒã
ããšãã°ããã®æ¹æ³ã§JSONãšããŠã«ãŒãããã®ããã€ãã®è¡ãæ³åããŠãã ããïŒ
demo=# create table routes_jsonb as
select to_jsonb(t) route
from (
select departure_airport_name, arrival_airport_name, days_of_week
from routes
order by flight_no limit 4
) t;
SELECT 4
demo=# select ctid, jsonb_pretty(route) from routes_jsonb;
ctid | jsonb_pretty
-------+-----------------------------------------------
(0,1) | { +
| "days_of_week": [ +
| 1 +
| ], +
| "arrival_airport_name": "", +
| "departure_airport_name": "-" +
| }
(0,2) | { +
| "days_of_week": [ +
| 2 +
| ], +
| "arrival_airport_name": "-", +
| "departure_airport_name": "" +
| }
(0,3) | { +
| "days_of_week": [ +
| 1, +
| 4 +
| ], +
| "arrival_airport_name": "", +
| "departure_airport_name": "-"+
| }
(0,4) | { +
| "days_of_week": [ +
| 2, +
| 5 +
| ], +
| "arrival_airport_name": "-", +
| "departure_airport_name": "" +
| }
(4 rows)
demo=# create index on routes_jsonb using gin(route);
CREATE INDEX
ã€ã³ããã¯ã¹ã¯æ¬¡ã®ããã«ãªããŸãã

çŸåšãããšãã°ããã®ãããªã¯ãšãªã¯ã€ã³ããã¯ã¹ã䜿çšããŠå®è¡ã§ããŸãã
demo=# explain (costs off)
select jsonb_pretty(route)
from routes_jsonb
where route @> '{"days_of_week": [5]}';
QUERY PLAN
---------------------------------------------------------------
Bitmap Heap Scan on routes_jsonb
Recheck Cond: (route @> '{"days_of_week": [5]}'::jsonb)
-> Bitmap Index Scan on routes_jsonb_route_idx
Index Cond: (route @> '{"days_of_week": [5]}'::jsonb)
(4 rows)
@>
æŒç®åã¯ãæå®ããããã¹ïŒ
"days_of_week": [5]
ïŒãååšãããã©ããããJSONããã¥ã¡ã³ãã®ã«ãŒããã確èªããŸãã ãã®å Žåãã¯ãšãªã¯1è¡ãè¿ããŸãã
demo=# select jsonb_pretty(route) from routes_jsonb where route @> '{"days_of_week": [5]}';
jsonb_pretty
----------------------------------------------
{ +
"days_of_week": [ +
2, +
5 +
], +
"arrival_airport_name": "-",+
"departure_airport_name": "" +
}
(1 row)
ã¯ãšãªã¯æ¬¡ã®ããã«å®è¡ãããŸãã
- æ€çŽ¢ã¯ãšãªïŒ
"days_of_week": [5]
ïŒãããèŠçŽ ïŒæ€çŽ¢ããŒïŒïŒ "days_of_week"ããã³ "5"ãéžæãããŸãã - ããŒããªãŒã«ã¯éžæãããããŒãå«ãŸããããããã«å¯ŸããŠTIDã®ãªã¹ããéžæãããŸãïŒã5ã-ïŒ0.4ïŒããã³ãdays_of_weekã-ïŒ0,1ïŒãïŒ0,2ïŒãïŒ0,3ïŒ ãïŒ0.4ïŒã
- èŠã€ãã£ããã¹ãŠã®TIDã®ãã¡ãæŽåæ§æ©èœã¯ãèŠæ±ãããªãã¬ãŒã¿ãŒã«é©åãããã®ãéžæããŸãã
@>
æŒç®åã®å Žåãæ€çŽ¢ã¯ãšãªã®ãã¹ãŠã®èŠçŽ ãå«ãŸãªãããã¥ã¡ã³ãã¯æããã«é©åã§ã¯ãªããããïŒ0.4ïŒã®ã¿ãæ®ããŸãã ãã ããã€ã³ããã¯ã¹ã§ã¯ãèŠã€ãã£ãèŠçŽ ãJSONããã¥ã¡ã³ãã§èŠã€ãã£ãé åºãæ確ã§ã¯ãªããããæ®ãã®TIDã¯ããŒãã«ã§å確èªããå¿
èŠããããŸãã
ããã¥ã¡ã³ãã§ä»ã®æŒç®åã®è©³çŽ°ããèªã¿ãã ããã
JSONãæäœããããã®éåžžã®æäœã«å ããŠãjsqueryæ¡åŒµæ©èœã¯é·ãéååšããŠãããããè±å¯ãªæ©èœïŒãããŠãã¡ããGINã€ã³ããã¯ã¹ã®ãµããŒãïŒãåããã¯ãšãªèšèªãå®çŸ©ããŠããŸãã 2016幎ã«ã¯ãç¬èªã®æäœã»ãããšSQL / JSONãã¹ã¯ãšãªèšèªãå®çŸ©ããæ°ããSQLæšæºããªãªãŒã¹ãããŸããã ãã®æšæºã®å®è£
ã¯æ¢ã«
å®äºããŠãããPostgreSQL 11ã§ã®ç»å ŽãæåŸ
ããŠããŸãã
å
åŽ
pageinspectæ¡åŒµæ©èœã䜿çšããŠãGINã€ã³ããã¯ã¹ã®å
éšã
確èªã§ã
ãŸã ã
fts=# create extension pageinspect;
CREATE EXTENSION
ã¡ã¿ããŒãžããã®æ
å ±ã¯ãäžè¬çãªçµ±èšã瀺ããŠããŸãã
fts=# select * from gin_metapage_info(get_raw_page('mail_messages_tsv_idx',0));
-[ RECORD 1 ]----+-----------
pending_head | 4294967295
pending_tail | 4294967295
tail_free_size | 0
n_pending_pages | 0
n_pending_tuples | 0
n_total_pages | 22968
n_entry_pages | 13751
n_data_pages | 9216
n_entries | 1423598
version | 2
ããŒãžæ§é ã¯ãvacuumãªã©ã®éåžžã®ããã°ã©ã ã«ãäžéæããšåŒã°ããç¹å¥ãªé åãæäŸã
ãŸãããã®é åã«ã¯ãã¢ã¯ã»ã¹ã¡ãœãããæ
å ±ãä¿åã§ããŸãã GINã®ãã®ããŒã¿ã¯ãgin_page_opaque_infoé¢æ°ã«ãã£ãŠç€ºãããŸãã ããšãã°ãã€ã³ããã¯ã¹ããŒãžã®æ§æãèŠã€ããããšãã§ããŸãã
fts=# select flags, count(*)
from generate_series(1,22967) as g(id), -- n_total_pages
gin_page_opaque_info(get_raw_page('mail_messages_tsv_idx',g.id))
group by flags;
flags | count
------------------------+-------
{meta} | 1
{} | 133 B-
{leaf} | 13618 B-
{data} | 1497 B- TID-
{data,leaf,compressed} | 7719 B- TID-
(5 rows)
gin_leafpage_itemsé¢æ°ã¯ã{dataãleafãcompressed}ããŒãžã«ä¿åãããŠããTIDã«é¢ããæ
å ±ãè¿ããŸãã
fts=# select * from gin_leafpage_items(get_raw_page('mail_messages_tsv_idx',2672));
-[ RECORD 1 ]---------------------------------------------------------------------
first_tid | (239,44)
nbytes | 248
tids | {"(239,44)","(239,47)","(239,48)","(239,50)","(239,52)","(240,3)",...
-[ RECORD 2 ]---------------------------------------------------------------------
first_tid | (247,40)
nbytes | 248
tids | {"(247,40)","(247,41)","(247,44)","(247,45)","(247,46)","(248,2)",...
...
ããã§ãTIDããªãŒã®ãªãŒãããŒãžã«ã¯ãå®éã«ã¯ããŒãã«è¡ãžã®åå¥ã®ãã€ã³ã¿ãŒã§ã¯ãªããå°ããªå§çž®ãªã¹ããå«ãŸããŠããããšãããããŸãã
ããããã£
ginã¢ã¯ã»ã¹ã¡ãœããã®ããããã£ãèŠãŠã¿ãŸãããïŒãªã¯ãšã¹ã
ã¯ä»¥åã«äžããããŸãã ïŒïŒ
amname | name | pg_indexam_has_property
--------+---------------+-------------------------
gin | can_order | f
gin | can_unique | f
gin | can_multi_col | t
gin | can_exclude | f
èå³æ·±ãããšã«ãGINã¯è€æ°åã€ã³ããã¯ã¹ã®äœæããµããŒãããŠããŸãã ãã®å Žåãéåžžã®BããªãŒãšã¯ç°ãªããè€åããŒã¯ä¿åãããŸããããèŠçŽ ã¯åé¢ãããŸãããåçªå·ã瀺ãããã ãã§ãã
ã€ã³ããã¯ã¹ããããã£ïŒ
name | pg_index_has_property
---------------+-----------------------
clusterable | f
index_scan | f
bitmap_scan | t
backward_scan | f
äžåºŠã«1ã€ã®çµæã®åºåïŒã€ã³ããã¯ã¹ã¹ãã£ã³ïŒã¯ãµããŒããããŠããªãããšã«æ³šæããŠãã ãããããããããã¹ãã£ã³ïŒããããããã¹ãã£ã³ïŒã®ã¿ãæ§ç¯ã§ããŸãã
åŸæ¹ã¹ãã£ã³ã¯ãµããŒããããŠããŸããããã®æ©èœã¯ã€ã³ããã¯ã¹ã¹ãã£ã³ã«ã®ã¿é¢é£ããããããããã¹ãã£ã³ã«ã¯é¢é£ããŸããã
åã¬ãã«ã®ããããã£ïŒ
name | pg_index_column_has_property
--------------------+------------------------------
asc | f
desc | f
nulls_first | f
nulls_last | f
orderable | f
distance_orderable | f
returnable | f
search_array | f
search_nulls | f
ããã§ã¯äœãå©çšã§ããŸããïŒãœãŒãïŒç解å¯èœïŒãã€ã³ããã¯ã¹ãã«ããŒãšããŠäœ¿çšïŒããã¥ã¡ã³ãèªäœã¯ã€ã³ããã¯ã¹ã«ä¿åãããŸããïŒãæªå®çŸ©ã®å€ã®æäœïŒè€ååã®èŠçŽ ã«ã¯æå³ããããŸããïŒããããŸããã
ãã®ä»ã®ããŒã¿å
äžéšã®ããŒã¿åã«GINãµããŒããè¿œå ããããã€ãã®æ¡åŒµæ©èœã次ã«ç€ºããŸãã
- pg_trgmã䜿çšãããšã3æåïŒãã©ã€ã°ã©ã ïŒã®äžèŽã·ãŒã±ã³ã¹ã®æ°ãæ¯èŒããããšã§ãåèªã®ãé¡äŒŒæ§ããå€æã§ããŸã ã 2ã€ã®ã¯ã©ã¹ã®æŒç®ågist_trgm_opsãšgin_trgm_opsãè¿œå ãããLIKEãšæ£èŠè¡šçŸã䜿çšããæ¯èŒãªã©ãããŸããŸãªæŒç®åããµããŒããããŸãã ãã®æ¡åŒµæ©èœã¯ãã¹ãã«ãã¹ã®åèªãææ¡ããããã«ããã«ããã¹ãæ€çŽ¢ãšçµã¿åãããŠäœ¿çšââã§ããŸãã
- hstoreã¯ããŒãšå€ã®ã¹ãã¬ãŒãžãå®è£
ããŸãã ãã®ããŒã¿åã«ã¯ãGINãå«ãããŸããŸãªã¢ã¯ã»ã¹æ¹æ³ã®æŒç®åã¯ã©ã¹ããããŸãã ãã ããjsonbããŒã¿åã®åºçŸã«ãããhstoreã䜿çšããç¹å¥ãªçç±ã¯ãããŸããã
- intarrayã¯ãæŽæ°é
åã®æ©èœãæ¡åŒµããŸãã ã€ã³ããã¯ã¹ãµããŒãã«ã¯ãGiSTãšGINïŒæŒç®åã¯ã©ã¹gin__int_opsïŒã®äž¡æ¹ãå«ãŸããŸãã
ãŸãã2ã€ã®æ¡åŒµæ©èœããã§ã«æ¬æã§èšåãããŠããŸãã
- btree_ginã¯ãéåžžã®ããŒã¿åã®GINãµããŒããè¿œå ããŠãè€ååãšãšãã«ãã«ãã«ã©ã ã€ã³ããã¯ã¹ã§äœ¿çšããŸãã
- jsqueryã¯ãJSONã¯ãšãªèšèªãšãã®ã€ã³ããã¯ã¹ãµããŒãçšã®æŒç®åã¯ã©ã¹ãå®çŸ©ããŸãã ãã®æ¡åŒµæ©èœã¯ãæšæºã®PostgreSQLãã£ã¹ããªãã¥ãŒã·ã§ã³ã®äžéšã§ã¯ãããŸããã
ç¶ç¶ãã ã