44

私は、レシーバーと呼ばれるjsonbフィールドを持つpostgresql 9.4データベースにテーブルを持っています。行の例:

[{"id": "145119603", "name": "145119603", "type": 2}]
[{"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "363058213", "name": "363058213", "type": 1}]
[{"id": "1427965764", "name": "1427965764", "type": 1}]
[{"id": "193623800", "name": "193623800", "type": 0}, {"id": "419955814", "name": "419955814", "type": 0}]
[{"id": "624635532", "name": "624635532", "type": 0}, {"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "791712670", "name": "791712670", "type": 0}]
[{"id": "895207852", "name": "895207852", "type": 0}]
[{"id": "144695994", "name": "144695994", "type": 0}, {"id": "384217055", "name": "384217055", "type": 0}]
[{"id": "1079725696", "name": "1079725696", "type": 0}]

id の値のリストがあり、jsonb フィールドの配列内で、そのリストの値のいずれかを持つオブジェクトを含む行を選択したいと考えています。

それは可能ですか?これを高速化するために作成できる GIN インデックスはありますか?

4

2 に答える 2

72

役立つ単一の操作はありませんが、いくつかのオプションがあります。

1.照会する ID の数が少ない (固定されている) 場合は、複数の包含演算子を;@>と組み合わせて使用​​できます。or例:

where data @> '[{"id": "1884595530"}]' or data @> '[{"id": "791712670"}]'

ここでは、単純なginインデックスがデータ列に役立ちます。

2. ID の数が可変の場合 (または ID が多数ある場合)、json[b]_array_elements()配列の各要素を抽出し、ID リストを作成してから、any-containment 演算子を使用してクエリを実行できます?|

select *
from   jsonbtest
where  to_json(array(select jsonb_array_elements(data) ->> 'id'))::jsonb ?|
         array['1884595530', '791712670'];

残念ながら、サブクエリを含む式をインデックス化することはできません。インデックスを付けたい場合は、関数を作成する必要があります。

create function idlist_jsonb(jsonbtest)
  returns jsonb
  language sql
  strict
  immutable
as $func$
  select to_json(array(select jsonb_array_elements($1.data) ->> 'id'))::jsonb
$func$;

create index on jsonbtest using gin (idlist_jsonb(jsonbtest));

この後、次のように ID を照会できます。

select *, jsonbtest.idlist_jsonb
from   jsonbtest
where  jsonbtest.idlist_jsonb ?| array['193623800', '895207852'];

:ここではドット表記/計算フィールドを使用しましたが、その必要はありません。

3.しかし、この時点では、json[b] に固執する必要はありません。PostgreSQL でもサポートされている単純なテキスト配列があります。

create function idlist_array(jsonbtest)
  returns text[]
  language sql
  strict
  immutable
as $func$
  select array(select jsonb_array_elements($1.data) ->> 'id')
$func$;

create index on jsonbtest using gin (idlist_array(jsonbtest));

そして、オーバーラップ配列演算子を使用して、この計算フィールドをクエリします&&

select *, jsonbtest.idlist_array
from   jsonbtest
where  jsonbtest.idlist_array && array['193623800', '895207852'];

: 私の内部テストでは、この後者のソリューションは jsonb バリアントよりも高いコストで計算されていますが、実際にはそれよりも少し高速です。パフォーマンスが本当に重要な場合は、両方をテストする必要があります。

于 2015-02-13T10:22:15.310 に答える