カスタムオペレーターを使用するクエリをサポートするインデックスを作成しようとしています。これはPostgresql 10.4にあります
this SO回答)のヒントに従って、テキスト配列内の要素に対して「LIKE」スタイルのマッチングを実行する演算子を作成しました。
CREATE FUNCTION reverse_like (text, text) returns boolean language sql
as $$ select $2 like $1 $$;
CREATE OPERATOR <~~ ( function =reverse_like, leftarg = text, rightarg=text );
上記の演算子を使用すると、次のようなことができます
SELECT 'ab%' <~~ ANY('{"abc","def"}');
配列列を含むsessions
というWebトラフィックアクセスのテーブルがあります。
CREATE TABLE sessions
(
session_id varchar(24) NOT NULL,
first_seen timestamp,
domains varchar[]
);
ドメイン列をクエリして、特定のドメイン(または部分的/ワイルドカードドメイン名)にアクセスしたかどうかを確認するには、次のようにします。
SELECT count(*)
FROM session_4070ba14_f081_41cb_9ef7_9dd385934da7
WHERE 'www.foo%' <~~ ANY(domains);
上記のクエリをGINインデックスで高速化したいと思います。だから私は次のようにインデックスを作成しました:
CREATE INDEX idx_domains ON session USING GIN(domains);
テーブルで分析を実行した後、set enable_seqscan = false;
postgresにこのインデックスを採用させることができません。常にseqscanを実行しています。 @>のような配列演算子の上記のインデックスを使用しますが、カスタムの<~~演算子には使用しません。
これは、GINインデックスがカスタムオペレーターの処理方法を認識していないためだと思います。オペレータークラスを作成し、それを使用して私のインデックスを作成する必要がありますか?または、関数インデックスを作成しますか?
GINインデックスについて考えることで、これを複雑にしてしまいました。配列全体のBツリーインデックスは正常に機能し、カスタムの<~~演算子をサポートします。
CREATE INDEX IF NOT EXISTS idx_domains2 ON session(domains );
select count(*)
from session
where 'www.foo%' <~~ ANY(domains);
Finalize Aggregate (cost=331523.11..331523.12 rows=1 width=8)
-> Gather (cost=331522.90..331523.11 rows=2 width=8)
Workers Planned: 2
-> Partial Aggregate (cost=330522.90..330522.91 rows=1 width=8)
-> Parallel Index Only Scan using idx_domains2 on session (cost=0.42..330200.52 rows=128952 width=0)
Filter: ('www.foo%'::text <~~ ANY ((domains)::text[]))
次のような式にインデックスを付けることはできません。
<constant><operator> ANY(<array column>)
唯一のチャンスは、式が次のようになるように演算子を定義することです。
<array column><operator><constant>
しかし、GIN演算子クラスを作成するということは、Cで拡張機能を作成することを意味します。それほど遠くに行きたくないと思います。
簡単な解決策は、そのようなことのために配列を使用しないようにデータモデルを変更することです。
トライグラムのサポートについては、 parray_gin拡張 を試すことができます
WHERE domains @@> ARRAY['www.foo%'];
プレフィックスマッチングを実行するだけの場合(trigramで提供されるものよりも効率的)、ピースを結合するCコードを記述せずにこれを行う方法はないと思います。次に、配列型を直接操作するので、ANYは必要なく、reverse_like演算子のメリットもまったくないと思います。