Back

The Duel of Data Structures: LSM Tree vs. B+ Tree

Jan 26 2024
10min
🕐 Current time : 29 Mar 2025, 05:04 AM
The full Astro logo.

LSM Tree: Write Like the Wind, Read with a Pause.

Imagine lightning-fast writes, like scribbling in a notepad. That’s an LSM tree. It prioritizes write speed by storing new data in temporary, in-memory structures. No slow disk writes slowing you down. But reading isn’t as immediate. Think back to flipping through that notepad – not exactly quick for finding specific notes. LSM trees need to periodically merge these notes into sorted files on disk, a process called compaction, to optimize for later reads.

B+ Tree: The Orderly Librarian

Think of a meticulously organized library with a helpful librarian (the B+ tree). Every book (data item) has its dedicated place, making searches a breeze. Need a specific title? The librarian guides you quickly through the alphabetized shelves. However, adding new books takes time – like carefully inserting them in the right order. Writes can be slower than with an LSM tree.

So before jumping on conclusion let’s implement and see one by one.

LSM Tree Structure:

Multiple levels of in-memory (MemTable) and disk-based (SSTables) components.

New writes go to MemTable, optimized for fast writes.

MemTable flushes to disk as SSTables when full.

SSTables are immutable and sequentially written for fast reads.

Periodic compaction merges sorted SSTables, removing duplicates and optimizing for reads.

class LSMTree {
    private MemTable memTable;
    private List<SSTable> levels; // Multiple levels of SSTables

    public void Insert(Key key, Value value) {
        memTable.Insert(key, value);
        if (memTable.IsFull()) {
            FlushMemTable();
        }
    }

    private void FlushMemTable() {
        SSTable ssTable = memTable.CreateSSTable();
        levels.Add(ssTable);
        memTable = new MemTable(); // Create a new empty MemTable
        if (levels.Count > MaxLevels) {
            CompactLevels();
        }
    }

    private void CompactLevels() {
        // Merge and sort SSTables from lower levels to higher levels, removing duplicates
        // This process optimizes read performance and controls disk usage
    }

    public Value Get(Key key) {
        Value value = memTable.Get(key);
        if (value == null) {
            // Search through SSTables in levels, starting from the newest
            // Use a merge-sort strategy to combine results efficiently
        }
        return value;
    }
}

Key Considerations for Implementation:

MemTable: Implement using a hash table or similar structure for fast writes.

SSTables: Use B-trees or other efficient on-disk data structures for reads.

Compaction: Choose a suitable compaction strategy (e.g., size-tiered, leveled) based on workload characteristics.

Merge-Sort: Implement efficient merge-sort algorithms for key-value pairs during compaction and reads.

Key Concepts for Implementing B + tree.

A balanced tree with variable-sized nodes.

Internal nodes store keys and pointers to child nodes.

Leaf nodes store keys and associated values.

All leaf nodes are at the same level, forming a linked list.

Key Considerations for Implementation:

MemTable: Implement using a hash table or similar structure for fast writes.

SSTables: Use B-trees or other efficient on-disk data structures for reads.

Compaction: Choose a suitable compaction strategy (e.g., size-tiered, leveled) based on workload characteristics.

Merge-Sort: Implement efficient merge-sort algorithms for key-value pairs during compaction and reads.

Key Operations:

Insert, Search, Delete, Range queries, Maintaining balance through splitting and merging nodes.

class BPlusTree {
    private Node root;
    private int order; // Maximum number of keys per node

    // Node structure (can be further refined for internal and leaf nodes)
    private class Node {
        public List<Key> Keys { get; set; }
        public List<Node> Children { get; set; } // Only for internal nodes
        public List<Value> Values { get; set; } // Only for leaf nodes
    }

    // Insert a key-value pair
    public void Insert(Key key, Value value) {
        Node leaf = FindLeafNode(key);
        InsertIntoLeaf(leaf, key, value);
        if (leaf.Keys.Count > order - 1) { // Split leaf if full
            SplitLeaf(leaf);
        }
    }

    // Search for a key
    public Value Search(Key key) {
        Node leaf = FindLeafNode(key);
        int index = leaf.Keys.BinarySearch(key);
        if (index >= 0) {
            return leaf.Values[index];
        } else {
            return null; // Key not found
        }
    }

    // Helper functions for node splitting, merging, etc.
    // ...
}

Key Implementation Considerations:

Node Management: Implement internal and leaf nodes with appropriate properties.

Searching: Use efficient algorithms like binary search within nodes.

Insertion and Deletion: Handle node splitting and merging to maintain balance.

Range Queries: Leverage the linked leaf nodes for efficient traversal.

so now for me it’s a draw, but with different prize categories. Here’s when each shines:

LSM Tree Wins:

Write-heavy workloads: Think social media feeds or banking transactions. You need to store data fast, even if reading it sometimes requires a moment of patience.

Scalability: As your data grows, LSM trees adapt gracefully. New “notepads” can be added seamlessly.

Durability: Even if the system crashes, data in the in-memory structures and partially-compacted files is often recoverable.

B+ Tree Wins:

Read-heavy workloads: Need lightning-fast searches? B+ trees are your allies. No merge delays, just straight to the data.

Predictable performance: Writes might be slower, but they’re consistent. No surprises, just reliable performance.

Efficiency: Once compacted, B+ trees offer space-efficient data storage. No duplicate scribbles in your library.

Ultimately, the choice is yours. Consider your application’s priorities. Need nimble writes over instant reads? The LSM tree beckons. Crave quick searches and predictable performance? The B+ tree awaits. Choose your champion wisely, and your database will be a champion in its own right.

Remember, there’s no one-size-fits-all solution. So, explore, experiment, and let the data structure duel guide you to the perfect fit for your database needs!💡

Read more in this Series:

Find me on

GitHub LinkedIn LinkedIn X Twitter
© 2022 to 2025 : Amit Prakash