<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Indexing on IT Comparison</title><link>https://comparison.metacog.co.kr/tags/indexing/</link><description>Recent content in Indexing on IT Comparison</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 06 Sep 2026 09:42:56 +0900</lastBuildDate><atom:link href="https://comparison.metacog.co.kr/tags/indexing/index.xml" rel="self" type="application/rss+xml"/><item><title>B-Tree vs LSM Tree: In-Place Updates vs Log-Structured Merges</title><link>https://comparison.metacog.co.kr/posts/2026-09-06-b-tree-vs-lsm-tree-in-place-updates-vs-log-structured-merges/</link><pubDate>Sun, 06 Sep 2026 09:42:56 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-09-06-b-tree-vs-lsm-tree-in-place-updates-vs-log-structured-merges/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;B-Trees and LSM Trees are the two dominant on-disk index structures used by databases, and they diverge on how they handle writes. A B-Tree performs &lt;strong class="kw"&gt;in-place updates&lt;/strong&gt; on a balanced page structure to keep reads fast, while an LSM Tree buffers writes in memory and reconciles them later through &lt;strong class="kw"&gt;background compaction&lt;/strong&gt;, trading read simplicity for write throughput.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;text x="160" y="24" text-anchor="middle" font-size="16" style="fill:var(--primary)"&gt;B-Tree&lt;/text&gt;&lt;text x="480" y="24" text-anchor="middle" font-size="16" style="fill:var(--primary)"&gt;LSM Tree&lt;/text&gt;&lt;rect x="120" y="40" width="80" height="30" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="160" y="59" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;root&lt;/text&gt;&lt;rect x="60" y="110" width="70" height="30" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="95" y="129" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;node&lt;/text&gt;&lt;rect x="180" y="110" width="70" height="30" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="215" y="129" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;node&lt;/text&gt;&lt;rect x="15" y="180" width="55" height="28" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="42" y="198" text-anchor="middle" font-size="10" style="fill:var(--content)"&gt;leaf&lt;/text&gt;&lt;rect x="80" y="180" width="55" height="28" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="107" y="198" text-anchor="middle" font-size="10" style="fill:var(--content)"&gt;leaf&lt;/text&gt;&lt;rect x="165" y="180" width="55" height="28" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="192" y="198" text-anchor="middle" font-size="10" style="fill:var(--content)"&gt;leaf&lt;/text&gt;&lt;rect x="230" y="180" width="55" height="28" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="257" y="198" text-anchor="middle" font-size="10" style="fill:var(--content)"&gt;leaf&lt;/text&gt;&lt;line x1="160" y1="70" x2="95" y2="110" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="160" y1="70" x2="215" y2="110" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="95" y1="140" x2="42" y2="180" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="95" y1="140" x2="107" y2="180" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="215" y1="140" x2="192" y2="180" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="215" y1="140" x2="257" y2="180" style="stroke:var(--border)" stroke-width="1.5"/&gt;&lt;line x1="107" y1="194" x2="150" y2="194" style="stroke:var(--compare-a)" stroke-width="1.5" stroke-dasharray="3,2"/&gt;&lt;text x="152" y="197" font-size="9" style="fill:var(--secondary)"&gt;update overwrites here&lt;/text&gt;&lt;text x="160" y="330" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;in-place updates, balanced traversal&lt;/text&gt;&lt;line x1="320" y1="30" x2="320" y2="340" style="stroke:var(--border)" stroke-width="1" stroke-dasharray="4,4"/&gt;&lt;defs&gt;&lt;marker id="arrow" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto"&gt;&lt;path d="M0,0 L8,4 L0,8 z" style="fill:var(--compare-b)"/&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;rect x="400" y="45" width="160" height="34" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="66" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;memtable (in-memory)&lt;/text&gt;&lt;line x1="480" y1="79" x2="480" y2="98" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrow)"/&gt;&lt;rect x="400" y="100" width="160" height="28" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="118" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;L0 SSTables&lt;/text&gt;&lt;line x1="480" y1="128" x2="480" y2="147" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrow)"/&gt;&lt;rect x="400" y="149" width="160" height="28" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="167" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;L1 SSTables&lt;/text&gt;&lt;line x1="480" y1="177" x2="480" y2="196" style="stroke:var(--compare-b)" stroke-width="1.5" marker-end="url(#arrow)"/&gt;&lt;rect x="400" y="198" width="160" height="28" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="216" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;L2 SSTables&lt;/text&gt;&lt;text x="480" y="248" text-anchor="middle" font-size="10" style="fill:var(--secondary)"&gt;compaction merges levels&lt;/text&gt;&lt;text x="480" y="330" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;sequential writes, background merge&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;B-Tree&lt;/th&gt;
&lt;th&gt;LSM Tree&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Write path&lt;/td&gt;
&lt;td&gt;Traverses the tree to locate the target page and updates it in place, splitting nodes as needed&lt;/td&gt;
&lt;td&gt;Appends the entry to an in-memory memtable plus a write-ahead log; no seek to the record&amp;rsquo;s final location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read path&lt;/td&gt;
&lt;td&gt;Single root-to-leaf traversal, O(log n) page reads from one location&lt;/td&gt;
&lt;td&gt;Checks the memtable then potentially multiple SSTables across levels, often aided by bloom filters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update/Delete handling&lt;/td&gt;
&lt;td&gt;Overwrites the existing value directly at its page&lt;/td&gt;
&lt;td&gt;Writes a new version or a tombstone; the old entry is only removed later during compaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-disk structure&lt;/td&gt;
&lt;td&gt;One mutable, balanced tree of fixed-size pages, always sorted&lt;/td&gt;
&lt;td&gt;Immutable sorted SSTable files organized into levels of increasing size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background maintenance&lt;/td&gt;
&lt;td&gt;Node splits and merges happen incrementally as part of each write&lt;/td&gt;
&lt;td&gt;Periodic compaction merges SSTables across levels and drops stale versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write amplification&lt;/td&gt;
&lt;td&gt;Low to moderate; occasional page rewrites and splits&lt;/td&gt;
&lt;td&gt;Higher; the same record can be rewritten multiple times as it moves through levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read amplification &amp;amp; space reclaim&lt;/td&gt;
&lt;td&gt;Minimal read amplification; deleted space is reclaimed immediately&lt;/td&gt;
&lt;td&gt;Higher read amplification from scanning multiple levels; space reclaimed only after compaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Range scans&lt;/td&gt;
&lt;td&gt;Efficient via sorted leaf pages linked in order&lt;/td&gt;
&lt;td&gt;Efficient within a level but requires merging sorted runs across levels&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A B-Tree updates data &lt;strong class="kw"&gt;in place&lt;/strong&gt;, while an LSM Tree defers changes through &lt;strong class="kw"&gt;append-only&lt;/strong&gt; writes to a memtable&lt;/li&gt;
&lt;li&gt;LSM Trees gain higher &lt;strong class="kw"&gt;write throughput&lt;/strong&gt; by avoiding random disk seeks, at the cost of ongoing &lt;strong class="kw"&gt;compaction&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;B-Trees give more predictable &lt;strong class="kw"&gt;read latency&lt;/strong&gt; since each key lives in exactly one place&lt;/li&gt;
&lt;li&gt;LSM read and space overhead comes from having to consult &lt;strong class="kw"&gt;multiple SSTable levels&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Deletes in an LSM Tree are recorded as &lt;strong class="kw"&gt;tombstones&lt;/strong&gt; rather than removed immediately&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;B-Tree&lt;/strong&gt;&lt;/p&gt;</description></item></channel></rss>