Why Indexing Matters
An index is a data structure that improves the speed of data retrieval operations on a database table at the cost of additional writes and storage space.
Without an index, the database must perform a Full Table Scan (), checking every row to find matches. A balanced-tree lookup can locate a key in comparisons, but returning K matches still requires work proportional to K; the planner may prefer a scan.
B-Tree Structure
Most relational databases (PostgreSQL, MySQL, Oracle) use B-Trees (specifically B+ Trees) for indexing.
Key Characteristics
- Balanced: All leaf nodes are at the same depth.
- Sorted: Data is kept capable of range queries.
- High Fanout: Nodes have many children (unlike binary trees), minimizing disk I/O.
Clustered vs Non-Clustered
Understanding this distinction is the single most important concept in physical database design.
| Feature | Clustered Index | Non-Clustered (Secondary) Index |
|---|---|---|
| Data Storage | Leaf nodes store the actual row data | Leaf nodes store a pointer (or PK) to the row |
| Quantity | Only 1 per table (organizes the table itself) | Many per table |
| Size | Large (contains all columns) | Small (contains indexed cols + PK) |
| Lookup | Direct access | 2 steps: Index Lookup → Key Lookup (in Clustered) |
[!TIP] Primary Keys are clustered indexes by default in MySQL (InnoDB) and SQL Server. In PostgreSQL, all indexes are secondary (heap table organization), though
CLUSTERcommand exists.
Composite Indexes
An index on multiple columns: CREATE INDEX idx_name_age ON users(last_name, age).
Leftmost Prefix Rule
Leading equality conditions usually narrow a B-tree scan most effectively. This is a planning rule of thumb, not an absolute prohibition on later columns: skip scans and index filtering depend on the database version and data distribution.
Given Index on (A, B, C):
| Query Condition | Uses Index? |
|---|---|
WHERE A=1 | ✅ Yes |
WHERE A=1 AND B=2 | ✅ Yes |
WHERE A=1 AND B=2 AND C=3 | ✅ Yes |
WHERE B=2 | May scan the index or use skip scan; inspect the plan |
WHERE A=1 AND C=3 | A narrows the scan; C may filter or further constrain it |
Visualizing Multi-Column Sort
Think of a phone book. It's sorted by Last Name, then First Name.
- Finding "Smith" is easy.
- Finding "John" (without knowing Last Name) is impossible without scanning everything.
Covering Indexes
A super-optimization. If the index contains all the columns needed for the query, the DB doesn't need to look up the table row at all!
Query: SELECT age FROM users WHERE last_name = 'Smith'
Index: (last_name, age)
The index has the requested columns. In PostgreSQL, an index-only scan may still visit heap pages to check visibility unless the visibility map permits skipping them.
Indexing Strategies
1. Cardinality
Index columns with high cardinality (many unique values like UserID, Email).
Low cardinality alone is not a reason to reject an index. A rare status value, a partial index, or a useful composite index can be selective even when a column has few distinct values.
2. Is NULL
B-Trees handle NULLs differently per DB.
- Oracle B-tree indexes omit entries where all indexed key columns are NULL; composite and function-based cases require care.
- PostgreSQL/MySQL/SQL Server: NULLs are indexed.
3. Write Penalty
Inserts and deletes generally add index maintenance; updates may affect relevant indexes or benefit from engine-specific optimizations such as PostgreSQL HOT.
- Too many indexes = Slow writes.
- Too few indexes = Slow reads.
Code Examples
SQL: Analyzing Execution Plans
-- 1. Create Table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255),
age INT,
created_at TIMESTAMP
);
-- 2. Populate 1M rows...
-- 3. Analyze Query without Index
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
-- Result: Seq Scan on users (cost=0.00..18334.00 rows=1)
-- Inspect actual timing and buffer reads on your data; this is not a benchmark result.
-- 4. Create Index
CREATE INDEX idx_email ON users(email);
-- 5. Analyze Again
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
-- Result: Index Scan using idx_email on users
-- Compare measured execution time, heap fetches, and buffer reads.
Hash Index (Key-Value)
Good for equality checks (=), useless for ranges (>, <).
Structure: Hash Table. lookup.
CREATE INDEX idx_session ON sessions USING HASH (session_id);
Interview Tips 💡
- "How does a B-Tree work?" — Explain "Balanced, Sorted, High Fanout". Differentiate from Binary Tree (depth).
- "What is the difference between Clustered and Non-Clustered?" — Clustered IS the table. Non-clustered points to the table.
- "What is a Composite Index?" — Explain the Leftmost Prefix Rule.
- "Why not index every column?" — Write amplification. Storage cost.
- "LSM Tree vs B-Tree?" — Compare page updates with buffered LSM writes and compaction. Read/write performance depends on access patterns and storage configuration.
Related Concepts
Sources and a design check
PostgreSQL multicolumn indexes covers leading columns and skip scans; index-only scans explains heap visibility checks. Compare plans before and after indexing using the same data and cache state, then measure the write penalty as well.
Keep reading
Consistent Hashing
How to add/remove servers without moving every single key. The ring, virtual nodes, placement and migration tradeoffs.
Database Sharding
How to split a massive database across multiple servers. Horizontal scaling strategies, challenges (Joins, ACID), and real-world algorithms used by Instagram, Vitess, and CockroachDB.
Vector Databases (AI/Embeddings)
Complete guide to vector databases optimized for AI embeddings and semantic search, covering vector similarity, approximate nearest neighbor algorithms (HNSW, IVF), and production implementations in Pinecone, Milvus, Weaviate, and pgvector powering LLM applications.
Write-Ahead Logging (WAL)
The backbone of database durability (ACID). How WAL ensures data isn't lost during crashes, implementation details (LSN, Checkpointing), and its role in replication.
ACID and BASE: Choose Guarantees per Operation
Distinguish transaction isolation, invariant preservation and replica freshness through a worked inventory example.
CRDTs (Real-time Collaboration)
How convergent data types merge offline changes, why removals need causal metadata, and how to test collaboration semantics without assuming business invariants are automatic.