←Back to Tutorials

Database Indexes: B-Trees, Composite Indexes & Performance

Master how indexes work under the hood with B-trees, composite index design, covering indexes, and when adding indexes makes your database slower.

90 minutes
7Detailed Sections
Senior Level

Suppose your table has 10 million rows and you need to find one user by email. Without an index, the database must scan row by row until it finishes the table.

That is a full table scan, and its cost grows linearly with table size. Small tables hide this problem, but once data grows, the same endpoint that felt fast in development can become painfully slow in production.

Indexes solve this by creating a separate, ordered lookup structure so the database can jump to matching rows instead of checking every row. Conceptually, it works like a book index: you locate the term once, then jump to the right pages.

The trade-off is important: indexes are not free metadata, they are real on-disk structures that consume storage, use memory in the buffer pool, and must be updated on every INSERT, UPDATE, and DELETE.

So indexing is a read-vs-write decision. In most read-heavy workloads, the read-time savings are worth the write overhead.

The key is to understand when an index reduces total cost and when it quietly adds operational drag.

Key Takeaways

1
Full Table Scan: Database reads every single row sequentiallyβ€”O(N) time complexity
2
Linear Growth Problem: 1M rows = 1 sec, 10M rows = 10 secβ€”performance degrades linearly
3
Production Impact: Same query that takes 3ms at 2 AM takes 12 seconds during peak traffic as data grows
4
Index = Separate Data Structure: Not magic, but a real sorted lookup structure stored on disk
5
Space-Time Tradeoff: Indexes trade disk space (20-50% of table size) for query speed
6
Memory Competition: Index pages compete for buffer pool space with table data
7
Write Cost: Every INSERT/UPDATE/DELETE must maintain all indexes on that table
8
Read-Heavy Workloads: Most web applications have 10:1 read:write ratioβ€”indexes win
9
Not Always Used: Query planner may skip index if returning >30% of rows (cheaper to scan)
10
Real-World Example: Production query dropped from 6 seconds to 8ms after adding one index

Visual Diagram


╔════════════════════════════════════════════════════════════╗
β•‘     πŸ“Š FULL TABLE SCAN vs INDEX LOOKUP                    β•‘
╠════════════════════════════════════════════════════════════╣
β•‘                                                            β•‘
β•‘  ❌ WITHOUT INDEX (Full Table Scan - O(N)):               β•‘
β•‘  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓    β•‘
β•‘  ┃ Row 1:          email = "alice@example.com"  ❌  ┃    β•‘
β•‘  ┃ Row 2:          email = "bob@example.com"    ❌  ┃    β•‘
β•‘  ┃ Row 3:          email = "carol@example.com"  ❌  ┃    β•‘
β•‘  ┃ Row 4-46:       ... scanning ...             ❌  ┃    β•‘
β•‘  ┃ Row 47:         email = "dana@example.com"   βœ…  ┃    β•‘
β•‘  ┃ Row 48-10M:     ... must check remaining ...  ❌  ┃    β•‘
β•‘  ┃ Row 10,000,000: email = "zoe@example.com"    ❌  ┃    β•‘
β•‘  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛    β•‘
β•‘  ⏱️  Time: O(N) β†’ 12 seconds at scale                     β•‘
β•‘  πŸ’Ύ I/O: 10 MILLION disk reads                             β•‘
β•‘                                                            β•‘
β•‘  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  β•‘
β•‘                                                            β•‘
β•‘  βœ… WITH INDEX (B-Tree Lookup - O(log N)):                β•‘
β•‘                                                            β•‘
β•‘              ╔════════════════╗                            β•‘
β•‘              β•‘  [ROOT NODE]   β•‘                            β•‘
β•‘              β•‘   Range: M-Z   β•‘                            β•‘
β•‘              β•šβ•β•β•β•β•β•β•β•¦β•β•β•β•β•β•β•β•β•                            β•‘
β•‘                      β•‘                                     β•‘
β•‘        ╔═════════════╩══════════════╗                      β•‘
β•‘        β•‘                            β•‘                      β•‘
β•‘   ╔════╩═════╗               ╔═════╩═════╗                β•‘
β•‘   β•‘   A-D    β•‘               β•‘    E-L    β•‘                β•‘
β•‘   β•šβ•β•β•β•¦β•β•β•β•β•β•β•               β•šβ•β•β•β•β•β•β•¦β•β•β•β•β•                β•‘
β•‘       β•‘                             β•‘                      β•‘
β•‘  ╔════╩════╗ ╔════════╗      ╔═════╩═════╗                β•‘
β•‘  β•‘  A-B    β•‘ β•‘  C-D   β•‘      β•‘   E-G     β•‘                β•‘
β•‘  β•‘         β•‘ β•‘  β¬… Hereβ•‘      β•‘           β•‘                β•‘
β•‘  β•šβ•β•β•β•β•β•β•β•β•β• β•šβ•β•β•β•β•¦β•β•β•β•      β•šβ•β•β•β•β•β•β•β•β•β•β•β•                β•‘
β•‘                   β•‘                                        β•‘
β•‘                   β–Ό                                        β•‘
β•‘            🎯 "dana@..." β†’ Row 47                          β•‘
β•‘                                                            β•‘
β•‘  πŸ“ Path: Root β†’ A-D β†’ C-D β†’ Row 47                       β•‘
β•‘  ⏱️  Time: O(log N) β†’ 3 milliseconds                      β•‘
β•‘  πŸ’Ύ I/O: Just 3-4 disk reads                               β•‘
β•‘                                                            β•‘
β•‘  πŸš€ Performance: 4000x faster (3ms vs 12s)                 β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

Sign in to unlock

Sign In Free