LSM-tree vs B-tree
LSM-Tree vs B-Tree
Learn how B-Trees update sorted pages in place, how Log-Structured Merge Trees buffer writes and flush immutable sorted files, and how their read paths, write paths, compaction, caching, range queries, deletions, and amplification trade-offs affect database performance.
Introduction
A database must perform two fundamental operations efficiently:
- Store new or updated data safely
- Find the required data quickly
Optimizing both operations simultaneously is difficult. A structure designed for predictable reads can require more work during writes. A structure designed for high write throughput can require additional work during reads and background maintenance.
B-Trees and Log-Structured Merge Trees, commonly called LSM-Trees, represent two important storage-engine approaches.
- B-Tree family: Maintains keys in page-oriented balanced structures and updates the relevant pages.
- LSM-Tree family: Buffers writes in memory, flushes sorted immutable files, and merges those files through background compaction.
Core idea: B-Trees organize data for direct and predictable reads. LSM-Trees transform incoming writes into buffered, sequential storage operations, but require reads and background compaction to work across multiple data structures.
Neither design is universally better. The correct choice depends on the workload's read-to-write ratio, key distribution, range-query requirements, update pattern, storage hardware, latency objectives, and operational capacity for background maintenance.
Prerequisites
| # | Prerequisite | Why It Is Needed |
|---|---|---|
| 1 | B-Tree indexes | B-Trees organize sorted keys into balanced, page-oriented tree structures. |
| 2 | Write-ahead logging | Both storage-engine families can use a durable log before acknowledging writes. |
| 3 | Memory and disk I/O | The designs make different use of memory buffers, random I/O, and sequential I/O. |
| 4 | Sorted data structures | Both approaches maintain ordered keys, but organize and update them differently. |
| 5 | Caching | Page caches, block caches, and memory tables significantly affect observed performance. |
| 6 | Access-pattern design | Storage-engine selection must be based on actual reads, writes, scans, and deletions. |
What Is a Storage Engine?
A storage engine is the database component responsible for organizing, persisting, reading, updating, and recovering stored data.
Application
|
v
Database API or query layer
|
v
Query execution
|
v
Storage engine
|
+-- Memory structures
+-- Indexes
+-- Transaction log
+-- Data files
+-- Cache
+-- Recovery logic
|
v
Persistent storage
The storage engine influences:
- Write throughput
- Point-read latency
- Range-scan performance
- Space utilization
- Read and write amplification
- Background I/O
- Crash recovery
- Deletion behaviour
- Storage-device endurance
What Is a B-Tree?
A B-Tree is a balanced search tree in which each node can contain several sorted keys and child references.
[40 | 80]
/ | \
/ | \
v v v
[10 | 20] [50 | 60] [90 | 100]
The tree remains balanced, meaning leaf nodes remain at the same depth. A high branching factor allows one node or storage page to direct searches across a large key range.
B-Tree Components
| Component | Purpose |
|---|---|
| Root node | Starting point for tree navigation |
| Internal node | Contains separator keys and references to child pages |
| Leaf node | Contains keys and record information or row references |
| Page | Fixed-size unit read from or written to storage |
| Page cache | Keeps frequently accessed pages in memory |
B+ Tree
Many database systems use a B+ Tree variation. Internal nodes guide navigation, while leaf pages contain record information and are commonly linked for ordered scanning.
Internal pages:
[40 | 80]
/ | \
v v v
Leaf pages:
[10, 20, 30] <-> [40, 50, 60] <-> [80, 90, 100]
Linked leaf pages make ordered range scans practical after the database locates the first matching key.
Terminology note: Database discussions sometimes use “B-Tree” as a broad term even when the implementation has B+ Tree characteristics. The exact page and record layout depends on the storage engine.
B-Tree Read Path
A point lookup starts at the root and follows the key ranges until reaching the appropriate leaf page.
Find key 52
Root page:
[40 | 80]
52 is between 40 and 80
|
v
Middle child page:
[45 | 50 | 52 | 60]
|
v
Key 52 found
If upper tree levels and frequently accessed leaves remain in the page cache, many reads can avoid physical storage access.
B-Tree Write Path
An insert or update finds the relevant page, modifies it in memory, and eventually persists the changed page according to the database's durability mechanism.
Application writes key 52
|
v
Write recovery information
to transaction log
|
v
Navigate to target leaf page
|
v
Modify page in memory
|
v
Persist changed page
according to storage-engine policy
If the target page has no space, the engine can split the page and update parent routing information.
Page Split
Before insert:
[10 | 20 | 30 | 40]
Insert:
25
Page is full
After split:
[10 | 20] [25 | 30 | 40]
\ /
\ /
Parent updated
Splits can propagate upward when a parent page also lacks space.
B-Tree Range Scan
B-Trees naturally maintain key ordering.
Query:
Keys from 40 through 75
Steps:
1. Navigate to first key greater than or equal to 40.
2. Read matching records in key order.
3. Continue through neighboring leaf pages.
4. Stop after key 75.
This makes B-Tree-family structures suitable for ordered indexes, prefix ranges, date ranges, and pagination using indexed keys.
What Is an LSM-Tree?
LSM means Log-Structured Merge. An LSM-Tree accepts new writes into an in-memory sorted structure and later flushes the accumulated data to immutable sorted files on persistent storage.
Write request
|
+-- Write-Ahead Log
|
v
Active Memtable
|
v
Immutable Memtable
|
v
Flush
|
v
Level 0 SST files
|
v
Background compaction
|
v
Lower-level SST files
These immutable sorted disk files are commonly called SSTables or sorted runs.
LSM-Tree Components
| Component | Purpose |
|---|---|
| Write-ahead log | Provides recovery information for accepted in-memory writes |
| Memtable | Maintains recent writes in an ordered in-memory structure |
| Immutable memtable | Frozen memory structure waiting to be flushed |
| SSTable | Immutable sorted key-value file on persistent storage |
| Level | Logical grouping of SSTables under a compaction strategy |
| Bloom filter | Helps skip files that definitely do not contain a requested key |
| Compaction process | Merges sorted files and removes obsolete versions when safe |
| Block cache | Keeps frequently read SSTable data blocks in memory |
LSM-Tree Write Path
Application writes key 52
|
v
Append write to WAL
|
v
Insert key into active memtable
|
v
Acknowledge according to durability policy
|
v
Memtable becomes full
|
v
Freeze memtable
|
v
Flush sorted contents to SSTable
|
v
Compact files in background
The incoming write does not need to locate and immediately rewrite its final on-disk position. The engine buffers many writes and writes them in sorted batches.
Memtable
A memtable is the active in-memory data structure receiving new writes.
Active memtable:
10 -> value A
20 -> value B
35 -> value C
52 -> value D
90 -> value E
The memtable maintains ordered keys so it can be flushed as an ordered on-disk structure.
Because memory is volatile, a durable LSM implementation commonly records writes in a write-ahead log before relying on the memtable.
SSTable
An SSTable is an immutable file containing keys in sorted order.
SSTable A:
10 -> value A
20 -> value B
35 -> value C
52 -> value D
90 -> value E
After an SSTable is created, its existing contents are not normally updated in place. Newer values are written to newer structures.
LSM-Tree Read Path
A point read must locate the newest visible value across memory and one or more disk files.
Read key 52
|
v
Check active memtable
|
+-- Found:
| return newest visible value
|
+-- Not found:
check immutable memtables
|
v
check recent SSTables
|
v
check lower levels
|
v
return newest matching value
or not found
The engine uses file metadata, indexes, caches, and Bloom filters to avoid searching every stored key.
Bloom Filters
A Bloom filter is a space-efficient probabilistic structure used to test whether a key might exist in a file.
Check Bloom filter for key 52
|
+-- Definitely absent:
| skip this SSTable
|
+-- Might exist:
inspect this SSTable
A standard Bloom filter can return a false positive, meaning that it says a key might exist when the key is absent. It should not return a false negative for an item inserted into a correctly functioning filter.
Bloom-filter rule: A negative result can avoid an unnecessary file lookup. A positive result still requires checking the underlying data.
Compaction
Compaction merges sorted files into new sorted files.
SSTable A:
10 -> value A1
30 -> value C1
50 -> value E1
SSTable B:
20 -> value B2
30 -> value C2
60 -> value F2
Compaction output:
10 -> value A1
20 -> value B2
30 -> value C2
50 -> value E1
60 -> value F2
During compaction, the engine can discard older overwritten versions when those versions are no longer required by snapshots, transactions, or recovery rules.
Compaction helps:
- Reduce the number of sorted runs inspected during reads
- Remove obsolete overwritten values
- Reclaim deleted data when safe
- Reduce space amplification
- Maintain the selected level or tier organization
Leveled Compaction
In leveled compaction, disk files are organized into levels with controlled size targets.
Level 0:
Recently flushed files
Keys can overlap
Level 1:
Larger sorted level
Ranges are controlled
Level 2:
Larger again
Level 3:
Largest and older data
When a level exceeds its configured target, selected files are merged with overlapping ranges in the next level.
General Benefit
Controlled overlap can reduce the number of files that a point read must inspect in lower levels.
General Cost
Existing data can be rewritten repeatedly as it is compacted through the levels.
Tiered Compaction
In a tiered strategy, several similarly sized sorted runs can accumulate before they are merged.
Tier:
Run A
Run B
Run C
Run D
|
v
Merge selected runs
|
v
Larger run
Allowing more runs can reduce immediate merge work, but reads and temporary storage usage can increase.
Compaction-strategy Comparison
| Area | Leveled Direction | Tiered Direction |
|---|---|---|
| Sorted runs | Controls overlap through levels | Allows several runs before merging |
| Read amplification | Can be lower after compaction | Can require checking more runs |
| Write amplification | Can rewrite data more frequently | Can defer some merge work |
| Space amplification | Can keep duplicate versions more controlled | Can temporarily retain more overlapping data |
Actual results depend on the database, configuration, key distribution, update workload, value size, and storage hardware.
Deletions and Tombstones
SSTables are immutable, so an LSM-Tree cannot immediately remove an older key from every existing file.
Instead, the engine writes a deletion marker commonly called a tombstone.
Older SSTable:
course-42 -> published course data
Newer structure:
course-42 -> TOMBSTONE
Read result:
Key is treated as deleted.
Compaction later removes the tombstone and older values when it is safe to do so.
Deletion rule: A successful logical delete does not necessarily mean the old bytes are removed from every SSTable immediately. Physical reclamation depends on compaction, snapshots, replication, and retention behaviour.
B-Tree vs LSM-Tree
| Area | B-Tree Family | LSM-Tree Family |
|---|---|---|
| Primary organization | Balanced page-oriented search tree | Memory tables plus immutable sorted runs |
| Incoming writes | Navigate to and modify relevant pages | Append to log and update in-memory sorted structure |
| Disk update style | Page-oriented updates | Flush new sorted files and compact later |
| Point-read path | Navigate one balanced tree | Check memory and potentially several sorted runs |
| Range scans | Navigate to start and continue through ordered leaves | Merge ordered results from memory and relevant SSTables |
| Background work | Page flushing, cleanup, and database-specific maintenance | Flushing and compaction are central operations |
| Deletion | Update pages and reclaim space according to engine behaviour | Write tombstone and reclaim older data during compaction |
| Common strength | Predictable point reads and ordered access | Buffered high-throughput writes |
| Common risk | Random page updates and page splits | Read amplification, compaction pressure, and temporary duplicate versions |
Amplification
Storage-engine analysis commonly examines three forms of amplification:
- Write amplification
- Read amplification
- Space amplification
Write Amplification
Write amplification measures how much physical storage writing occurs compared with the logical data written by the application.
\[ WriteAmplification = \frac{ PhysicalBytesWritten }{ LogicalBytesWritten } \]
B-Tree Sources
- Write-ahead or recovery log
- Modified data or index page
- Page split
- Parent-page update
- Database-specific full-page or checkpoint behaviour
LSM-Tree Sources
- Write-ahead log
- Memtable flush
- Repeated compaction across levels or tiers
- Index and metadata updates
Important: LSM-Trees optimize the incoming write path by batching and sequentially flushing data, but they do not eliminate write amplification. Compaction can rewrite the same data multiple times.
Read Amplification
Read amplification describes the additional storage work required to satisfy a logical read.
\[ ReadAmplification = \frac{ PhysicalDataRead }{ LogicalDataRequested } \]
A B-Tree lookup follows a small number of tree pages. An LSM point lookup can inspect memory and several candidate SSTables.
LSM implementations reduce read amplification using:
- Bloom filters
- Per-file key-range metadata
- Sparse indexes
- Block indexes
- Block cache
- Leveled organization
- Compaction
Space Amplification
Space amplification compares physical storage consumption with the logical live dataset.
\[ SpaceAmplification = \frac{ PhysicalStorageUsed }{ LogicalLiveDataSize } \]
LSM-Trees can temporarily retain older versions, tombstones, overlapping files, and compaction outputs. B-Tree engines can have partially filled pages, obsolete row versions, free space, and database-specific maintenance overhead.
The Amplification Trade-off
More aggressive LSM compaction:
- Fewer files to inspect
- Better controlled space usage
- More background rewriting
Less aggressive LSM compaction:
- Less immediate rewriting
- More sorted runs
- More possible read work
- More temporary duplicate data
Storage engines balance read, write, and space amplification rather than minimizing all three independently.
Point-read Comparison
B-Tree
Root
|
v
Internal page
|
v
Leaf page
|
v
Record
LSM-Tree
Memtable
|
v
Immutable memtable
|
v
Recent SSTables
|
v
Lower-level SSTables
|
v
Newest visible record
Caches and Bloom filters can make many LSM reads efficient, but the underlying read path has more possible locations to consider.
Range-scan Comparison
B-Tree Range Scan
Find first key
|
v
Read ordered leaf entries
|
v
Continue through adjacent leaves
|
v
Stop after end key
LSM Range Scan
Read matching memtable range
|
+-- Matching SSTable range A
+-- Matching SSTable range B
+-- Matching SSTable range C
|
v
Merge sorted iterators
|
v
Apply newest-version and tombstone rules
|
v
Return ordered result
Compaction style, overlapping files, cache state, scan width, and key distribution strongly affect LSM range-scan performance.
Write-latency Behaviour
LSM writes commonly have a short foreground path followed by background flushing and compaction.
Foreground:
WAL + memtable
Background:
Flush + compaction
This separation can provide high write throughput, but background work eventually must keep pace with incoming data.
Write Stalls
If flushing or compaction cannot keep up, the engine can accumulate too many immutable memtables or level-zero files.
Incoming write rate increases
|
v
Memtables fill faster
|
v
More SSTables reach Level 0
|
v
Compaction falls behind
|
v
Read amplification increases
|
v
Engine slows or stalls writes
to let background work catch up
Monitoring only foreground write latency can miss the growing compaction backlog that precedes a stall.
Latency Variability
Both designs can experience latency variation, but the causes differ.
| Storage Family | Possible Latency Sources |
|---|---|
| B-Tree | Cache misses, page splits, checkpoints, lock contention, and storage-page writes |
| LSM-Tree | Cache misses, several SSTable checks, flushes, compaction, write stalls, and tombstone-heavy scans |
Evaluate median and high-percentile latency under sustained workloads rather than relying only on average latency.
Caching
B-Tree Cache
A B-Tree page cache can retain root, internal, index, and frequently accessed leaf pages.
Page cache:
Root page
Hot internal pages
Frequently accessed leaves
Recently accessed data pages
LSM Cache
An LSM implementation can use several memory structures.
Memory:
Active memtable
Immutable memtables
Block cache
Index blocks
Bloom filters
File metadata
Storage-engine comparisons should include realistic cache sizes and warm-up conditions.
Crash Recovery
Both designs can use write-ahead logging, although their complete recovery procedures differ.
Conceptual B-Tree Recovery
Committed log records
|
v
Recover page-oriented changes
|
v
Restore transactionally valid state
Conceptual LSM Recovery
Existing SSTables remain present
|
v
Replay required WAL records
|
v
Rebuild lost memtable state
|
v
Resume flushing and compaction
Durability is determined by the database's acknowledgment and logging configuration, not by the tree name alone.
Updates and Multiple Versions
B-Tree Direction
Locate page containing key
|
v
Update record or record reference
|
v
Persist changed page
according to engine policy
LSM Direction
Older value remains in SSTable
|
v
Newer value written to memtable
|
v
Read returns newest visible version
|
v
Compaction later removes obsolete value
Snapshot isolation and multi-version concurrency can retain older versions longer in either database family.
Secondary Indexes
Secondary indexes introduce additional write and storage work regardless of the engine family.
Base record write
|
+-- Primary structure update
+-- Secondary index 1 update
+-- Secondary index 2 update
+-- Secondary index 3 update
In a B-Tree-oriented engine, each index can involve page-oriented updates. In an LSM-oriented engine, each index can have its own memtable, SSTables, compaction, cache, and write amplification.
Index rule: Every secondary index should support a verified access pattern. Unused indexes increase storage, write, compaction, replication, backup, and maintenance work.
Write-heavy Workloads
LSM-oriented engines are often considered for workloads with sustained ingestion or many inserts and updates.
Examples include:
- Activity streams
- Telemetry
- Event ingestion
- Time-series data
- Large distributed key-value workloads
- Ingestion-heavy analytical pipelines
The complete workload still matters. Heavy updates and deletes can generate tombstones and substantial compaction work.
Read-heavy Workloads
B-Tree-oriented engines are often a natural fit when the workload emphasizes predictable point lookups, ordered scans, relational indexes, and frequent reads.
Examples include:
- Transactional application lookups
- Indexed account and order retrieval
- Ordered pagination
- Frequent range queries
- Workloads with several relational indexes
An LSM engine can also serve read-heavy applications when properly compacted, indexed, cached, and configured. The choice must be benchmarked rather than inferred only from a general rule.
Selection Guidance
| Requirement | Likely Direction |
|---|---|
| Sustained high-volume writes | Evaluate an LSM-oriented engine |
| Predictable point reads | Evaluate a B-Tree-oriented engine |
| Frequent ordered range scans | B-Tree is a natural starting point, but test the actual engine |
| High ingestion with mostly exact-key reads | LSM can be a strong candidate |
| Many updates and deletes | Compare page maintenance with tombstone and compaction cost |
| Strict high-percentile latency objective | Test compaction, checkpoint, cache-miss, and stall behaviour |
| Limited background I/O capacity | Evaluate whether compaction can remain healthy |
| SSD endurance is important | Measure actual physical write amplification |
Benchmarking Requirements
Do not benchmark only one read or one insert.
A realistic evaluation should include:
- Expected dataset size
- Realistic key and value sizes
- Expected read-to-write ratio
- Insert, update, and delete mix
- Point reads
- Range scans
- Existing secondary indexes
- Working-set size
- Cache size
- Concurrent clients
- Sustained test duration
- Compaction or checkpoint activity
- Storage-device characteristics
- Failure and restart behaviour
Important Measurements
- Read throughput
- Write throughput
- Median latency
- High-percentile latency
- Physical bytes read
- Physical bytes written
- Database size
- Cache hit rate
- Compaction or checkpoint backlog
- Write-stall duration
- CPU utilization
- Temporary storage requirement
Monitoring a B-Tree-oriented Engine
Monitor:
- Page-cache hit rate
- Logical and physical reads
- Page splits
- Index fragmentation or free-space behaviour
- Checkpoint activity
- Transaction-log growth
- Index usage
- Lock or latch waits
- Storage read and write latency
- Database and index size
Monitoring an LSM-oriented Engine
Monitor:
- Memtable size and count
- Flush rate
- Level-zero file count
- Compaction queue and pending bytes
- Compaction read and write throughput
- Write amplification
- Read amplification
- Space amplification
- Bloom-filter usefulness
- Block-cache hit rate
- Tombstone count
- Write stalls
- Per-level storage size
- Background-thread saturation
Alert Conditions
For B-Tree-oriented storage, alert when:
- Page-cache hit rate decreases unexpectedly
- Storage read latency increases
- Page splits or index growth increase sharply
- Transaction-log or checkpoint pressure grows
- Lock or latch waits exceed the objective
For LSM-oriented storage, alert when:
- Level-zero file count approaches the stall threshold
- Compaction cannot keep pace with incoming writes
- Pending compaction bytes grow continuously
- Write stalls occur
- Read amplification increases
- Tombstone-heavy reads become slow
- Temporary compaction space becomes insufficient
Troubleshooting Slow Reads
B-Tree Checklist
- Verify that the query uses the intended index.
- Inspect the query plan.
- Check page-cache effectiveness.
- Check storage read latency.
- Check table and index statistics.
- Check range selectivity.
- Check lock and latch waits.
- Check whether the query reads many non-covering data pages.
LSM-Tree Checklist
- Check the active and immutable memtables.
- Check the number of candidate SSTables.
- Check Bloom-filter and block-cache behaviour.
- Check level-zero file count.
- Check compaction backlog.
- Check tombstone density.
- Check whether the range touches several overlapping files.
- Check storage bandwidth consumed by compaction.
Troubleshooting Slow Writes
B-Tree Checklist
- Check transaction-log latency.
- Check page splits.
- Check the number of maintained secondary indexes.
- Check lock and latch contention.
- Check checkpoint and page-flush pressure.
- Check storage random-write latency.
- Check whether keys create an insertion hotspot.
LSM-Tree Checklist
- Check WAL latency.
- Check memtable flush rate.
- Check immutable-memtable backlog.
- Check level-zero file count.
- Check compaction throughput.
- Check write stalls and throttling.
- Check storage free space for compaction.
- Check whether secondary indexes multiply the write load.
Common LSM-Tree and B-Tree Mistakes
Assuming LSM-Trees Have No Write Amplification
LSM-Trees batch incoming writes, but compaction can rewrite stored data several times.
Assuming B-Trees Perform One Physical Write per Update
Logging, page writes, splits, parent updates, checkpoints, and secondary indexes can create additional physical work.
Benchmarking Only an Empty Database
A small tree or an LSM engine without significant compaction pressure does not represent steady-state performance.
Measuring Only Average Latency
Compaction, checkpoints, page splits, cache misses, and write stalls can appear primarily in high-percentile latency.
Ignoring the Cache
Page cache, block cache, index blocks, Bloom filters, and memtables can dominate observed read behaviour.
Ignoring Range Queries
Point-read benchmarks do not reveal the cost of merging several sorted runs during an LSM range scan.
Ignoring Deletes
Tombstones and obsolete versions can increase LSM read and compaction work until they are safely reclaimed.
Ignoring Secondary Indexes
Every secondary index introduces its own storage, write, cache, recovery, and maintenance costs.
Giving Compaction No Resource Headroom
Foreground writes can appear successful until background compaction falls behind and the engine begins throttling or stalling.
Tuning from Generic Values
Appropriate memtable, cache, level, compaction, page, and concurrency settings depend on the workload and storage environment.
Choosing from Database Labels
A database product can use several storage structures or provide configurable engines. Verify the actual engine and configuration.
Ignoring Recovery and Restoration
Read and write benchmarks do not prove that the database can recover after failure or restore from backup correctly.
Recommended Test Cases
| Test | Expected Evidence |
|---|---|
| Sequential inserts | Write throughput and storage behaviour are measured |
| Random inserts | Page and compaction behaviour under distributed keys is observed |
| Random updates | Write amplification and high-percentile latency are measured |
| Point reads | Cache-hit and cache-miss latency are measured separately |
| Range scans | Ordered scan latency is measured at several range sizes |
| Delete-heavy workload | Tombstone or space-reclamation behaviour is observed |
| Sustained ingestion | The engine reaches steady state without an uncontrolled backlog |
| Compaction pressure | Read and write latency remain within tested limits |
| Storage nearly full | Maintenance and compaction failure behaviour is documented |
| Restart after accepted writes | Acknowledged data is recovered according to the durability contract |
| Secondary-index workload | Additional write and storage cost is measured |
| Backup restore | Restored data and indexes pass integrity and query checks |
Best Practices
Recommended Practices
- Identify the actual storage engine used by the database.
- Measure point reads, range scans, inserts, updates, and deletes separately.
- Include WAL and durability costs in write tests.
- Run benchmarks long enough to include maintenance work.
- Measure median and high-percentile latency.
- Test both warm-cache and cold-cache behaviour.
- Measure physical read, write, and storage amplification.
- Monitor B-Tree page splits, cache behaviour, and checkpoint pressure.
- Monitor LSM memtables, Level 0, compaction, tombstones, and write stalls.
- Maintain free storage and I/O headroom for background maintenance.
- Keep only secondary indexes supporting verified access patterns.
- Use Bloom filters for appropriate LSM point-read workloads.
- Select compaction strategy from reads, writes, updates, deletes, and scans.
- Do not assume that buffered writes remove durability requirements.
- Verify deletion and storage-reclamation behaviour.
- Test representative key and value sizes.
- Test the expected concurrency and traffic distribution.
- Test crash recovery and backup restoration.
- Reevaluate configuration when the workload changes.
- Choose the complete database system, not only the tree structure.
Practice Exercise
Compare B-Tree-oriented and LSM-Tree-oriented storage for the activity system of your online learning platform.
Requirements
- Generate course and learner activity records.
- Use realistic tenant, course, learner, and event keys.
- Test sequential event ingestion.
- Test random learner-progress updates.
- Test point lookup by activity ID.
- Test activity retrieval for one learner.
- Test activity retrieval over a date range.
- Test deletion of expired activity records.
- Add one secondary access path.
- Measure write throughput.
- Measure point-read and range-scan latency.
- Measure high-percentile latency.
- Measure physical bytes read and written.
- Observe page splits or compaction activity.
- Observe performance after the dataset exceeds memory.
- Test restart and recovery.
- Document which engine better satisfies each access pattern.
Comparison Template
| Workload Area | B-Tree Observation | LSM-Tree Observation |
|---|---|---|
| Point-read latency | Record measured cache-hit and cache-miss results | Record measured cache, Bloom-filter, and SSTable results |
| Write throughput | Record page and log behaviour | Record WAL, memtable, flush, and compaction behaviour |
| Range scans | Record ordered-leaf scan performance | Record sorted-run merge performance |
| Updates | Record page modifications and splits | Record new versions and compaction cost |
| Deletes | Record logical and physical reclamation behaviour | Record tombstone and compaction behaviour |
| Steady-state latency | Include checkpoints and full dataset size | Include compaction and Level 0 pressure |
| Storage overhead | Measure pages, indexes, logs, and free space | Measure SSTables, obsolete versions, tombstones, and compaction space |
Frequently Asked Questions
What is a B-Tree?
A B-Tree is a balanced, ordered, page-oriented search structure containing several keys and child references per node.
What is an LSM-Tree?
An LSM-Tree buffers writes in an ordered memory structure, flushes immutable sorted files, and merges those files through background compaction.
Why are LSM-Trees suitable for write-heavy workloads?
Incoming writes can be logged, buffered in memory, and flushed in sorted batches instead of immediately updating their final on-disk locations.
Why can B-Trees provide predictable point reads?
A lookup follows a balanced path through routing pages to the appropriate leaf page.
What is a memtable?
A memtable is an ordered in-memory structure that receives recent LSM-Tree writes before they are flushed to persistent storage.
What is an SSTable?
An SSTable is an immutable file containing keys in sorted order.
What is compaction?
Compaction merges sorted files, reorganizes levels or tiers, and removes obsolete values and tombstones when safe.
What is a tombstone?
A tombstone is a deletion marker that hides an older value until compaction can safely reclaim the old data.
What is write amplification?
Write amplification is the ratio of physical storage bytes written to logical application bytes written.
Do LSM-Trees always write less data?
No. They batch incoming writes, but compaction can rewrite the same data several times.
Are B-Trees always better for reads?
Not automatically. Cache size, query type, range width, storage hardware, engine implementation, and workload concurrency affect the result.
How should I choose between them?
Compare sustained writes, point reads, range scans, updates, deletions, amplification, storage cost, recovery, and high-percentile latency using representative data and traffic.
Key Takeaway
B-Trees maintain a balanced page-oriented structure that supports direct point lookup and ordered range traversal, but writes can modify pages, update logs, and cause page splits. LSM-Trees accept writes through a WAL and memtable, flush immutable sorted files, and reorganize them through compaction. This provides an efficient buffered write path but introduces read, space, and compaction trade-offs. Bloom filters, caches, indexes, levels, and compaction policies reduce LSM read costs, while page caches and high fan-out make B-Tree reads efficient. Do not select an engine from a simple “reads versus writes” rule. Benchmark the complete database under steady-state load, including cache misses, range scans, secondary indexes, deletes, checkpoints, compaction, write stalls, recovery, and physical storage amplification.