$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[July 23, 2025] PostgreSQL

PostgreSQL btree_gin and btree_gist Indexes

PostgreSQL btree_gin and btree_gist Indexes

────────────────────────────────────────────────────────

PostgreSQL btree_gin and btree_gist Indexes

Tip: Enable Extension

CREATE EXTENSION btree_gin;
CREATE EXTENSION btree_gist;

Gotcha: GIN Index on Regular Columns

CREATE INDEX idx_posts_title_gin ON posts USING gin (title btree_gin_ops);

Allows GIN indexes on text columns.

Tip: Multi-Column GIN

CREATE INDEX idx_posts_multi ON posts USING gin (category_id, status);

Efficient for queries filtering on multiple columns.

Gotcha: GiST for Range Queries

CREATE INDEX idx_posts_views_gist ON posts USING gist (int4range(views, views));

Useful for range overlap queries.

Tip: Combined Indexes

btree_gin allows combining B-tree and GIN operations in a single index.

Gotcha: Index Size

GIN indexes are larger than B-tree indexes. Use when query patterns justify the overhead.

Tip: EXPLAIN (ANALYZE, BUFFERS) Is Your Best Friend

For query debugging, always use EXPLAIN (ANALYZE, BUFFERS) instead of plain EXPLAIN. The BUFFERS option shows hit/miss rates for every node, revealing whether your indexes are actually in memory.

Tip: Partial Indexes Are Underutilized

CREATE INDEX ON orders (status) WHERE status = 'pending' creates a tiny index that covers only the rows your query needs. It's faster to scan and cheaper to maintain than a full-column index.

Gotcha: NULL Sorting Is Non-Obvious

By default, NULLs sort AFTER non-null values in ascending order. ORDER BY col DESC puts NULLs FIRST. Use NULLS LAST or NULLS FIRST to be explicit.

Senior Insight

The btree_gin and btree_gist extensions enable GIN and GiST indexes on multiple columns that include range conditions. Standard B-tree indexes only support =, <, >, and BETWEEN. With btree_gist, you can create a GiST index on (daterange, status) that efficiently supports queries like 'find active bookings in a date range'. I use these for scheduling and calendar applications where multi-column range queries are the norm.

Source: pganalyze Blog (https://pganalyze.com/blog), PostgreSQL Docs (https://www.postgresql.org/docs/current/), Crunchy Data Blog (https://www.crunchydata.com/blog)

────────────────────────────────────────────────────────
<-- back to posts