Overview

A GIN index creates one entry per element of a composite value, so a single row can add hundreds of entries. Add one once full-text search, JSONB containment, or array overlap queries show sequential scans, and expect larger indexes and slower writes in exchange. Confirm the planner uses it with EXPLAIN (query-plan).

Rules

  • Operators: @@ for tsvector; @>, <@, ?, ?|, ?&, @?, @@ for jsonb (default jsonb_ops); @>, <@, && for arrays. jsonb_path_ops is smaller and faster but supports only @>, @?, and @@.
  • fastupdate (default on) buffers inserts in a pending list that vacuum or gin_clean_pending_list() merges; a large pending list slows queries.
  • GiST updates and builds faster than GIN, but GIN answers large-vocabulary text queries faster.
  • Build on live tables with CREATE INDEX CONCURRENTLY.
CREATE INDEX idx_articles_fts ON articles USING gin (search_vec);
SELECT id FROM articles WHERE search_vec @@ to_tsquery('english', 'postgres & index');
 
CREATE INDEX idx_events_data ON events USING gin (data);
SELECT * FROM events WHERE data @> '{"type": "purchase"}';