create temp table fact as select generate_series(1,999) f1, generate_series(1,999) f2; insert into fact select s,null from generate_series(1,999) s; insert into fact select null,s from generate_series(1,999) s; create index f_f1 on fact(f1); create index f_f2 on fact(f2); analyze fact; create temp table dim as select s, s::text t from generate_series(1,999) s; alter table dim add primary key(s), add unique (t); create temp view denorm as select f.*, d1.t t1, d2.t t2, array[f1,f2] ident_ids from fact f left join dim d1 on f1=d1.s left join dim d2 on f2=d2.s ; -- Fast explain analyze select count(*) from denorm where 1 in (f1,f2); explain analyze select count(*) from denorm where '1' in (t1); -- Slow explain analyze select count(*) from denorm where '1' in (t1,t2); CREATE FUNCTION ident_ids( idents text[] ) RETURNS int[] STABLE LANGUAGE sql AS $$ SELECT array( SELECT s FROM dim WHERE t = ANY(idents) ) $$; CREATE FUNCTION ident_ids( idents text ) RETURNS int[] STABLE LANGUAGE sql AS $$ SELECT ident_ids( ('{' || idents || '}')::text[] ) $$; explain analyze select count(*) from denorm where ident_ids && ident_ids('42,84,128'); \echo ERROR OK here on version >= 10 create index fact__f_array on fact using gin ((array[f1,f2]) _int4_ops); -- pre 10.0 \echo ERROR OK here on version < 10 create index fact__f_array on fact using gin ((array[f1,f2]) array_ops); -- 10.0 explain analyze select count(*) from denorm where ident_ids && ident_ids('42,84,128');