試してみる価値はあると思います。いくつかのテスト (100000 レコード、JSON 配列の最大 10 要素) を作成し、それがどのように機能するかを確認しました。
create table test1 (id serial primary key, data json);
create table test1_altnames (id int, name text);
create or replace function array_from_json(_j json)
returns text[] as
$func$
select array_agg(x.elem::text)
from json_array_elements(_j) as x(elem)
$func$
language sql immutable;
with cte as (
select
(random() * 100000)::int as grp, (random() * 1000000)::int as name
from generate_series(1, 1000000)
), cte2 as (
select
array_agg(Name) as "AltNames"
from cte
group by grp
)
insert into test1 (data)
select row_to_json(t)
from cte2 as t
insert into test1_altnames (id, name)
select id, json_array_elements(data->'AltNames')::text
from test1
create index ix_test1 on test1 using gin(array_from_json(data->'AltNames'));
create index ix_test1_altnames on test1_altnames (name);
JSON のクエリ (私のマシンでは 30 ミリ秒) :
select * from test1 where '{489147}' <@ array_from_json(data->'AltNames');
"Bitmap Heap Scan on test1 (cost=224.13..1551.41 rows=500 width=36)"
" Recheck Cond: ('{489147}'::text[] <@ array_from_json((data -> 'AltNames'::text)))"
" -> Bitmap Index Scan on ix_test1 (cost=0.00..224.00 rows=500 width=0)"
" Index Cond: ('{489147}'::text[] <@ array_from_json((data -> 'AltNames'::text)))"
名前付きのクエリ テーブル (私のマシンでは15ms ):
select * from test1 as t where t.id in (select tt.id from test1_altnames as tt where tt.name = '489147');
"Nested Loop (cost=12.76..20.80 rows=2 width=36)"
" -> HashAggregate (cost=12.46..12.47 rows=1 width=4)"
" -> Index Scan using ix_test1_altnames on test1_altnames tt (cost=0.42..12.46 rows=2 width=4)"
" Index Cond: (name = '489147'::text)"
" -> Index Scan using test1_pkey on test1 t (cost=0.29..8.31 rows=1 width=36)"
" Index Cond: (id = tt.id)"
また、名前 ( ) を持つテーブルに行を挿入/削除するにはコストがかかるためtest1_altnames
、単に行を選択するよりも少し複雑です。個人的には、JSON を使用したソリューションが好きです。