B-Tree Indexes
B-Tree is the most common index type in relational databases.
B-Tree Structure
[50]
/ \
[20,30] [60,80]
/ | \\ / | \
[10] [25] [40] [55] [70] [90]
- Balanced tree
- All leaves at same depth
- Sorted data
- O(log n) lookups
How B-Tree Index Works
Table: users (1 million rows)
Index: idx_users_email ON users(email)
Query: SELECT * FROM users WHERE email = 'alice@example.com'
Without Index:
- Full table scan: 1 million rows checked
- Time: 500ms
With B-Tree Index:
- Index lookup: log2(1M) ≈ 20 comparisons
- Time: 0.5ms
1000x improvement!
B-Tree Operations
Search: O(log n)
- Navigate tree from root to leaf
- Find matching entries
Insert: O(log n)
- Find correct leaf position
- Insert new entry
- Split leaf if full
Delete: O(log n)
- Find entry
- Remove from leaf
- Merge if needed
Creating B-Tree Index
-- Single column
CREATE INDEX idx_users_email ON users(email);
-- Multiple columns (composite)
CREATE INDEX idx_users_name_email ON users(name, email);
-- Partial index
CREATE INDEX idx_active_users ON users(email) WHERE active = true;
-- Unique index
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);
B-Tree Best Practices
- Index columns used in WHERE: Speed up filters
- Index columns used in JOINs: Speed up joins
- Index columns used in ORDER BY: Speed up sorting
- Don't over-index: Each index slows writes
- Monitor index usage: Remove unused indexes
Hash Indexes
Hash indexes use hash tables for exact-match lookups.
Hash Index Structure
Hash Function: hash(email) → bucket
Bucket 0: [alice@a.com → Row 1]
Bucket 1: [bob@b.com → Row 2]
Bucket 2: [charlie@c.com → Row 3]
O(1) lookup for exact match
Hash vs B-Tree
| Aspect | Hash | B-Tree |
|---|---|---|
| Lookup | O(1) exact match | O(log n) range |
| Range queries | Not supported | Supported |
| Ordering | Not maintained | Sorted |
| Partial match | Not supported | Supported |
| Memory | Lower | Higher |
When to Use Hash Index
Use Hash Index when:
- Only exact-match queries (=)
- No range queries needed
- No ordering required
- High read throughput needed
Examples:
- Session lookup by ID
- User lookup by email
- Cache key lookup
Don't use Hash Index when:
- Range queries (>, <, BETWEEN)
- ORDER BY needed
- Prefix matching (LIKE 'abc%')
Hash Index in Practice
-- PostgreSQL Hash Index
CREATE INDEX idx_users_email_hash ON users USING hash(email);
-- Query using hash index
SELECT * FROM users WHERE email = 'alice@example.com'; -- Uses hash index
SELECT * FROM users WHERE email > 'a'; -- Does NOT use hash index
Hash Index Limitations
1. No range queries
WHERE id > 100 -- Can't use hash index
2. No ORDER BY
ORDER BY email -- Can't use hash index
3. No partial matching
WHERE email LIKE '%@example.com' -- Can't use hash index
4. Hash collisions
Multiple keys → same bucket
Resolution: chaining or open addressing
Composite Indexes
Composite indexes include multiple columns in a single index.
Composite Index Structure
Index on (name, email, age):
Sorted by:
1. name (primary)
2. email (secondary)
3. age (tertiary)
Alice, a@b.com, 25
Alice, c@d.com, 30
Bob, b@c.com, 28
Charlie, e@f.com, 22
Leftmost Prefix Rule
Index: (name, email, age)
Can use index:
✓ WHERE name = 'Alice'
✓ WHERE name = 'Alice' AND email = 'a@b.com'
✓ WHERE name = 'Alice' AND email = 'a@b.com' AND age = 25
Cannot use index:
✗ WHERE email = 'a@b.com' (skipped name)
✗ WHERE age = 25 (skipped name, email)
Composite Index Examples
-- Index for common query
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
-- Query uses index
SELECT * FROM orders
WHERE user_id = 123
ORDER BY created_at DESC;
-- Index for search
CREATE INDEX idx_products_category_price ON products(category, price);
-- Query uses index
SELECT * FROM products
WHERE category = 'electronics'
ORDER BY price;
Composite Index Best Practices
1. Column Order Matters
- Most selective column first
- Most frequently queried column first
2. Covering Index
- Include all columns needed by query
- Avoids table lookup
Example:
CREATE INDEX idx_covering ON users(name, email, age);
SELECT name, email, age FROM users WHERE name = 'Alice';
-- Index covers query, no table access needed
3. Index Size
- More columns = larger index
- Balance between coverage and size
Index Selectivity
Selectivity measures how many distinct values an index has.
Selectivity Formula
Selectivity = Number of Distinct Values / Total Rows
Example:
- email: 1M distinct values / 1M rows = 1.0 (highly selective)
- gender: 2 distinct values / 1M rows = 0.000002 (low selectivity)
- age: 100 distinct values / 1M rows = 0.0001
Selectivity Impact
High Selectivity (email):
- Many distinct values
- Index very effective
- Each lookup returns few rows
Low Selectivity (gender):
- Few distinct values
- Index less effective
- Each lookup returns many rows
- Full scan might be faster
Selectivity and Index Choice
| Selectivity | Index Type | Example |
|---|---|---|
| High (>0.1) | B-Tree | email, user_id |
| Medium (0.01-0.1) | B-Tree | age, status |
| Low (<0.01) | Consider skip | gender, boolean |
Index Cardinality
Cardinality = Number of distinct values
High cardinality: email, UUID, timestamp
Medium cardinality: age, price
Low cardinality: boolean, status, gender
Index on low cardinality:
- May not be used by query planner
- Consider partial index instead
Partial Indexes
-- Index only active users
CREATE INDEX idx_active_email ON users(email) WHERE active = true;
-- Smaller, more selective index
-- Only indexes rows where active = true
-- Query must match WHERE clause
SELECT * FROM users WHERE active = true AND email = 'x'; -- Uses index
SELECT * FROM users WHERE active = false AND email = 'x'; -- Does NOT
Index Monitoring
-- PostgreSQL: Check index usage
SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read
FROM pg_stat_user_indexes
ORDER BY idx_scan DESC;
-- Remove unused indexes
DROP INDEX idx_unused;
-- Check index size
SELECT indexname, pg_size_pretty(pg_relation_size(indexname::regclass))
FROM pg_indexes
WHERE tablename = 'users';
Index Best Practices
- Index high-selectivity columns: Most effective
- Monitor index usage: Remove unused indexes
- Use composite indexes wisely: Follow leftmost prefix
- Consider partial indexes: For filtered queries
- Balance index count: Each index slows writes
Practice Problems
Design a scalable Indexing system. Cover high-level architecture, data model, and API design.
Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliabilityHow would you scale Indexing to handle 10x the current load? Identify bottlenecks and solutions.
Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decompositionAnalyze potential failure modes for Indexing and design mitigation strategies.
Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradationQuiz
1. What is the time complexity of a B-Tree index lookup?
2. When should you use a hash index instead of B-Tree?
3. What is the leftmost prefix rule?
4. What is index selectivity?
Flashcards
Question
What is a B-Tree index?
Click to reveal answer
Answer
A balanced tree index providing O(log n) lookups. Supports range queries, ORDER BY, and partial matching. Most common index type in SQL databases.
Question
When should you use a hash index?
Click to reveal answer
Answer
For exact-match lookups only (= operator). O(1) performance but doesn't support range queries, ORDER BY, or partial matching.
Question
What is the leftmost prefix rule?
Click to reveal answer
Answer
Composite indexes can only be used if query includes leftmost columns. Index (name, email) works for WHERE name='x' but not WHERE email='x'.
Question
What is index selectivity?
Click to reveal answer
Answer
Ratio of distinct values to total rows. High selectivity (email, UUID) = effective index. Low selectivity (gender, boolean) = less effective.
Question
What is Indexing?
Click to reveal answer
Answer
Indexing is a key concept in system design.
Revision Notes
Key Takeaways
- 1.B-Tree indexes provide O(log n) lookups and support range queries
- 2.Hash indexes provide O(1) exact-match but no range support
- 3.Composite indexes follow leftmost prefix rule
- 4.High selectivity indexes are more effective
- 5.Monitor and remove unused indexes to maintain write performance
Interview Tips
- •Always discuss indexing strategy for database design
- •Explain why you chose specific index types
- •Consider query patterns when designing indexes
- •Mention index monitoring and maintenance
Cheat Sheet
Indexing - Cheat Sheet
B-Tree Index:
- O(log n) lookups
- Supports range, ORDER BY, partial match
- Most common index type
Hash Index:
- O(1) exact match
- No range, ORDER BY, or partial match
- Use for simple lookups
Composite Index:
- Multiple columns in one index
- Leftmost prefix rule applies
- Column order matters
Selectivity:
- High (>0.1): Very effective index
- Low (<0.01): Consider partial index
Best Practices:
- Index high-selectivity columns
- Monitor and remove unused indexes
- Follow leftmost prefix rule
- Consider partial indexes
- Balance index count vs write performance