これはかなり恐ろしいスキーマです。複数の値を次の場所に保存するように変更すると、最良の結果が得られます。
これらはすべて、非常に単純で健全な SQL 式を使用して必要なものを決定することを可能にし、大きなテーブルでのパフォーマンスを向上させるために (子テーブルの通常の b ツリー インデックスを介して、配列と hstore の GiST または GIN インデックスを介して) インデックス付け可能です。 .
そのままでももちろん可能ですが、パフォーマンスは悲惨なものになります。1 つの方法は、 を使用regexp_split_to_array
して列を配列に変換してから、配列演算子を使用してオーバーラップをテストすることです。
この SQLFiddle デモを参照してください。このデモでは、拡張テスト セットを使用しています。これは、問題を実証するのに十分ではなかったためです。
「いずれかのセットが列に表示されます」( %%
) と「すべてのセットが列に表示されます」 ( ) の両方を示しまし@>
た。
設定:
CREATE TABLE test(gah text);
INSERT INTO test(gah) VALUES
('adaf**5013**dad344'),
('23**aab**yyyy'),
('zzz**402dha**vuuuda'),
('no**matches**here**lalala'),
('5013**aab**402dha'),
('402dha**aab**somethingelse**5013'),
('402dha**aab**5013');
デモ:
regress=> SELECT gah FROM test
WHERE regexp_split_to_array(gah, '\*\*') && ARRAY['5013', 'aab', '402dha'];
gah
----------------------------------
adaf**5013**dad344
23**aab**yyyy
zzz**402dha**vuuuda
5013**aab**402dha
402dha**aab**somethingelse**5013
402dha**aab**5013
(6 rows)
regress=> SELECT gah FROM test
WHERE regexp_split_to_array(gah, '\*\*') @> ARRAY['5013', 'aab', '402dha'];
gah
----------------------------------
5013**aab**402dha
402dha**aab**somethingelse**5013
402dha**aab**5013
(3 rows)
驚くべきことに、PostgreSQL の式インデックスのサポートを利用することで、このクエリに役立つインデックスを実際に作成できます。もちろん、それができるからといって、それが良いアイデアであるとは限りません。
regress=> CREATE INDEX test_glah_resplit_gin ON test
USING GIN(( regexp_split_to_array(gah, '\*\*') ));
CREATE INDEX
regress=> -- Only for testing purposes, don't use in production:
regress=> SET enable_seqscan = off;
SET
regress=> explain SELECT gah FROM test WHERE regexp_split_to_array(gah, '\*\*') @> ARRAY['5013', 'aab', '402dha'];
QUERY PLAN
-----------------------------------------------------------------------------------------------
Bitmap Heap Scan on test (cost=16.00..20.02 rows=1 width=32)
Recheck Cond: (regexp_split_to_array(gah, '\*\*'::text) @> '{5013,aab,402dha}'::text[])
-> Bitmap Index Scan on test_glah_resplit_gin (cost=0.00..16.00 rows=1 width=0)
Index Cond: (regexp_split_to_array(gah, '\*\*'::text) @> '{5013,aab,402dha}'::text[])
(4 rows)
regress=> explain SELECT gah FROM test WHERE regexp_split_to_array(gah, '\*\*') && ARRAY['5013', 'aab', '402dha'];
QUERY PLAN
-----------------------------------------------------------------------------------------------
Bitmap Heap Scan on test (cost=16.00..20.02 rows=1 width=32)
Recheck Cond: (regexp_split_to_array(gah, '\*\*'::text) && '{5013,aab,402dha}'::text[])
-> Bitmap Index Scan on test_glah_resplit_gin (cost=0.00..16.00 rows=1 width=0)
Index Cond: (regexp_split_to_array(gah, '\*\*'::text) && '{5013,aab,402dha}'::text[])
(4 rows)
GIN インデックスは更新に費用がかかるため、このアプローチを使用すると、 insert
/に対してかなりのパフォーマンスの代償を払うことになります。update
これは通常の配列にも当てはまります。その場でそれらを作成するために使用regexp_split_to_table
すると、少し悪化します。GIN のヒントとGIN インデックスの概要を参照してください。
たとえば、テスト テーブルに 100 万行を挿入するINSERT INTO test(gah) SELECT 'aaaaabbbbb'||(x::text) FROM generate_series(1,1000000) x;
と、GIN インデックスが配置されている場合は 22 秒、ドロップした場合は 1.6 秒かかりました。ただし、値が均一であるため、これは特に悪いケースになる可能性があります。