🎉 75% of content is free forever — Unlock Premium from $10/mo →
CW
💼 Servicesℹ️ About✉️ ContactView Pricing Plansfrom $10

Advanced Indexing Strategies — B-Tree, GIN, GiST, Partial & Covering Indexes

Advanced SQLPerformance⭐ Premium

Advertisement

Advanced Indexing Strategies

Advanced SQL

Index Like a Pro

Indexes are the single most impactful performance tool in SQL. The right index can turn a 30-second query into a 30-millisecond one. But choosing the wrong index wastes space and slows writes.

  • B-Tree — Default for equality and range queries
  • GIN — Inverted index for arrays, JSON, full-text search
  • GiST — Geospatial and range types
  • BRIN — Block range index for large, naturally ordered tables
  • Partial — Index only a subset of rows

The key to indexing: understand your query patterns, then create indexes that match them.


Index Types at a Glance

B-TreeEquality: = Range: <, >, BETWEENSort: ORDER BYLIKE 'abc%'Default choiceMost queriesBalanced R/WGINArrays: @>, &&JSONB: @?, @@Full-text: @@ContainsSemi-structuredSlow writesFast readsGiSTGeospatial: &&Range typesNearest neighborST_DWithinSpatial dataApproximateLossyBRINTime-seriesAppend-onlyNatural orderTiny index sizeLarge tablesBlocks-levelMin/max per blockPartialWHERE activeWHERE status='new'Selective rowsSmaller indexSubset queriesTiny & fastWHERE clause match

B-Tree Index Fundamentals

-- Standard B-tree index
CREATE INDEX idx_users_email ON users (email);

-- Composite B-tree index (column order matters!)
CREATE INDEX idx_orders_customer_date ON orders (customer_id, order_date DESC);

-- Unique constraint (creates unique B-tree index)
ALTER TABLE users ADD CONSTRAINT uk_users_email UNIQUE (email);

ℹ️

Key Insight: B-tree indexes support equality and range queries. The column order in composite indexes matters: put equality columns first, then range columns, then sorting columns.


Partial Indexes

-- Index only active users (smaller & faster)
CREATE INDEX idx_active_users ON users (email)
WHERE status = 'active';

-- Index recent orders
CREATE INDEX idx_recent_orders ON orders (customer_id, order_date)
WHERE order_date > CURRENT_DATE - INTERVAL '90 DAY';

-- Index pending tasks
CREATE INDEX idx_pending_tasks ON tasks (assigned_to, priority)
WHERE status = 'pending';

GIN Index for Arrays and JSON

-- GIN index for array containment
CREATE INDEX idx_user_tags ON users USING GIN (tags);

-- GIN index for JSONB
CREATE INDEX idx_user_data ON users USING GIN (data);

-- GIN with specific operator class (smaller, faster)
CREATE INDEX idx_user_data_path ON users USING GIN (data jsonb_path_ops);

GiST Index for Geospatial

-- GiST index for geometric data
CREATE INDEX idx_locations ON stores USING GiST (
  ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)
);

-- GiST index for range types
CREATE INDEX idx_booking_dates ON bookings USING GiST (
  tsrange(check_in, check_out)
);

Expression Indexes

-- Index on function result
CREATE INDEX idx_users_lower_email ON users (LOWER(email));

-- Index on computed value
CREATE INDEX idx_orders_total ON orders (
  (quantity * unit_price * (1 - discount))
);

-- Index on date extraction
CREATE INDEX idx_orders_month ON orders (EXTRACT(MONTH FROM order_date));

⚠️

Performance Tip: Expression indexes are only used when the query uses the exact same expression. Make sure your query matches the index definition precisely — LOWER(email) = 'test' uses the index, but email = 'TEST' does not.


Covering Indexes (INCLUDE)

-- Covering index with INCLUDE (avoids table lookups)
CREATE INDEX idx_orders_covering ON orders (customer_id, order_date)
INCLUDE (total_amount, status);

-- Verify index-only scan
EXPLAIN (ANALYZE)
SELECT order_date, total_amount, status
FROM orders
WHERE customer_id = 123;

BRIN Index for Large Tables

-- Block Range Index for time-series data (tiny index size)
CREATE INDEX idx_events_timestamp ON events USING BRIN (event_time);

-- BRIN with custom page range
CREATE INDEX idx_logs_time ON logs USING BRIN (created_at)
WITH (pages_per_range = 32);

Multi-Column Index Strategy

-- Optimal column order:
-- 1. Equality predicates (status = 'active')
-- 2. Range predicates (order_date > '2024-01-01')
-- 3. Sort columns (ORDER BY customer_id)
-- 4. SELECT list columns (INCLUDE for covering)

CREATE INDEX idx_optimal ON orders (
  status,           -- Equality
  order_date,       -- Range
  customer_id       -- Sort
) INCLUDE (total_amount);

Index Maintenance

-- Check index size
SELECT indexname, pg_size_pretty(pg_relation_size(indexname::regclass)) AS size
FROM pg_indexes WHERE tablename = 'employees';

-- Rebuild bloated indexes
REINDEX INDEX idx_users_email;

-- Check index usage statistics
SELECT indexrelname, idx_scan, idx_tup_read, idx_tup_fetch,
  pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_stat_user_indexes
WHERE relname = 'employees'
ORDER BY idx_scan DESC;

Concurrent Index Creation

-- Create index without locking table (production-safe)
CREATE INDEX CONCURRENTLY idx_large_table ON large_table (column_name);

-- Check for invalid indexes
SELECT indexrelname, indisvalid, indisready
FROM pg_stat_user_indexes
INNER JOIN pg_index ON indexrelid = pg_stat_user_indexes.indexrelid
WHERE NOT indisvalid;

Quiz: Test Your Knowledge


Follow-Up Questions

  1. When would you choose a GIN index over a B-tree index?
  2. How do partial indexes improve query performance?
  3. Explain the difference between GiST and SP-GiST indexes.
  4. How do you determine the optimal column order for composite indexes?
  5. What's the impact of index maintenance on write performance?

Key Takeaways

  • B-Tree — Default choice for equality, range, and sort queries
  • GIN — Best for arrays, JSONB, and full-text search (inverted index)
  • GiST — Geospatial, range types, nearest-neighbor searches
  • BRIN — Tiny indexes for large, naturally ordered tables (time-series)
  • Partial — Index only a subset of rows (WHERE clause) — smaller & faster
  • Covering — INCLUDE columns to avoid table lookups (index-only scan)
  • Column order — Equality → Range → Sort → INCLUDE
🔒

Premium Content

Advanced Indexing Strategies — B-Tree, GIN, GiST, Partial & Covering Indexes

You've previewed the first section. Unlock this full lesson and 900+ advanced tutorials with a Premium plan.

🎯End-to-end Projects
💼Interview Prep
📜Certificates
🤝Community Access

Already a member? Log in

Advertisement