I have a query that is supposed to use a bunch of trigram indexes to speed up ILIKE clauses. This works as long as there isn't a subquery in one of the where terms. I've simplified my query and can reproduce the issue with a trivial subquery and a simple ILIKE comparison. The actual query has several more ILIKE comparisons and some subqueries that actually do something useful. I'm using Postgres 9.6. The index is defined like this: CREATE INDEX datasets_notes_trgm_idx ON datasets USING GIN(notes gin_trgm_ops); The following query is slow and doesn't use any of my indexes: SELECT * FROM datasets WHERE datasets.notes ILIKE '%test%' OR datasets_id IN (SELECT 1) Explain output for this query: "Seq Scan on datasets (cost=0.01..21156.99 rows=53076 width=1428) (actual time=0.042..155.697 rows=1098 loops=1)" " Filter: ((notes ~~* '%test%'::text) OR (hashed SubPlan 1))" " Rows Removed by Filter: 104967" " Buffers: shared hit=19634" " SubPlan 1" " -> Result (cost=0.00..0.01 rows=1 width=4) (actual time=0.003..0.006 rows=1 loops=1)" "Planning time: 0.980 ms" "Execution time: 158.579 ms" The follow query is fast and uses the index: SELECT * FROM datasets WHERE datasets.notes ILIKE '%test%' Explain output for this query: "Bitmap Heap Scan on datasets (cost=28.68..360.36 rows=87 width=1428) (actual time=1.056..11.763 rows=1097 loops=1)" " Recheck Cond: (notes ~~* '%test%'::text)" " Rows Removed by Index Recheck: 16" " Heap Blocks: exact=1053" " Buffers: shared hit=1097" " -> Bitmap Index Scan on datasets_notes_trgm_idx (cost=0.00..28.66 rows=87 width=0) (actual time=0.732..0.732 rows=1113 loops=1)" " Index Cond: (notes ~~* '%test%'::text)" " Buffers: shared hit=12" "Planning time: 0.869 ms" "Execution time: 14.563 ms" Replacing the subquery with a static list of ids also works and the trigram index is used. SELECT * FROM datasets WHERE datasets.notes ILIKE '%test%' OR datasets_id IN (1,2,3) Explain output for this query: "Bitmap Heap Scan on datasets (cost=41.98..385.13 rows=90 width=1428) (actual time=0.593..7.194 rows=1100 loops=1)" " Recheck Cond: ((notes ~~* '%test%'::text) OR (datasets_id = ANY ('{1,2,3}'::integer[])))" " Rows Removed by Index Recheck: 16" " Heap Blocks: exact=1054" " Buffers: shared hit=1107" " -> BitmapOr (cost=41.98..41.98 rows=90 width=0) (actual time=0.428..0.428 rows=0 loops=1)" " Buffers: shared hit=21" " -> Bitmap Index Scan on datasets_notes_trgm_idx (cost=0.00..28.66 rows=87 width=0) (actual time=0.401..0.401 rows=1113 loops=1)" " Index Cond: (notes ~~* '%test%'::text)" " Buffers: shared hit=12" " -> Bitmap Index Scan on datasets_pkey (cost=0.00..13.28 rows=3 width=0) (actual time=0.019..0.019 rows=3 loops=1)" " Index Cond: (datasets_id = ANY ('{1,2,3}'::integer[]))" " Buffers: shared hit=9" "Planning time: 0.543 ms" "Execution time: 10.034 ms" The actual performance difference is much larger in the full query that uses several more ILIKE comparisons. Why does the subquery force a sequential scan on my query? And how can I avoid this and add subqueries while still using my trigram indexes?