Indexing
B-Tree, Hash, and GIN Indexes
Understanding standard and advanced database indexing strategies.
1. Introduction
PostgreSQL supports multiple index types optimized for different query patterns. B-Tree handles equality and range queries. Hash is for equality-only lookups. GIN handles full-text search, JSONB, and arrays. GiST handles geometric data. BRIN handles time-series. Choosing the right type is critical.
2. Why It Matters
- Query pattern matching: Each index type excels at specific patterns. Wrong type = poor performance.
- Storage efficiency: BRIN indexes on time-series can be 1000x smaller than B-tree equivalents.
- Advanced queries: GIN enables JSONB containment, array operations, and full-text search.
3. Real-World Analogy
A library has different lookup systems: alphabetical card catalog (B-tree), barcode scanner for exact ISBN (Hash), subject keyword index (GIN), and date-stamped new arrivals shelf (BRIN).
4. How It Works
5. Internal Architecture
6. Visual Explanation
7. Practical Example
8. Common Mistakes
Using Hash when B-tree works better
Hash indexes only support equality. B-tree handles equality AND range. Use Hash only for pure equality on high-cardinality columns.
GIN write overhead
GIN indexes are 2-3x larger and slower to update. Use fastupdate = on for write-heavy tables.
9. Quick Quiz
Q1: Which index for a 100-billion row log table filtered by timestamp?
Answer: BRIN. Timestamps are monotonically increasing, so BRIN stores only block-level min/max. 100B rows might need only 10MB vs 3GB for B-tree.
10. Scenario-Based Challenge
Challenge: Product Search Engine Indexing
Design indexes for: exact SKU lookup, price range filtering, full-text search, tag filtering (array), and category+price combined filtering.
11. Debugging Exercise
GIN index on TEXT isn't working with @@ operator. Why?
Fix: Index to_tsvector('english', content) instead of raw content.
12. Interview Questions
Q1: When would you choose BRIN over B-tree?
A: When the column is physically correlated with disk order (timestamps, auto-increment IDs). BRIN stores min/max per block range — for 1TB tables, BRIN might use 1MB vs 10GB for B-tree.
Q2: How does GIN handle JSONB queries?
A: GIN creates an inverted index of all key-value pairs. Containment queries look up each pair and intersect results — much faster than scanning all documents.
13. Production Considerations
- GIN fastupdate: Enable pending list batching to reduce write amplification on high-insert tables.
- BRIN autosummarize: Enable auto-updating of block range summaries for new inserts.
- Multiple index types: Use B-tree for IDs, GIN for JSONB, BRIN for timestamps on the same table.
- pg_trgm extension: Adds trigram GIN indexes for LIKE/ILIKE queries.