GGistDev

Indexes

Indexes speed up reads by organizing data for efficient lookup and sorting.

B-tree basics

  • Default index type for equality and ORDER BY
  • Useful for range queries (>, <, BETWEEN)
CREATE INDEX idx_users_email ON users(email);

Multi-column indexes

Order matters: leftmost columns are most selective.

CREATE INDEX idx_orders_customer_created ON orders(customer_id, created_at DESC);

Supports queries filtering customer_id and ordering by created_at.

Partial/filtered indexes

-- Postgres
CREATE INDEX idx_orders_paid ON orders(created_at) WHERE status = 'paid';

Smaller, targeted indexes for common predicates.

Covering indexes (include)

-- Postgres INCLUDE, SQL Server INCLUDE
CREATE INDEX idx_orders_lookup ON orders(customer_id) INCLUDE (total, status);

Allows queries to be satisfied from the index alone.

Expression and functional indexes

-- Postgres
CREATE INDEX idx_users_email_lower ON users((lower(email)));

Enable case-insensitive lookups.

Maintenance and trade-offs

  • Indexes slow down writes (INSERT/UPDATE/DELETE)
  • Monitor unused indexes; drop those that don’t pay for themselves
  • Reindex or rebuild when fragmentation is severe (engine-dependent)

Summary

  • Start with B-tree, add multi-column matching common filters/sorts
  • Use partial/covering indexes and expressions to target hot paths