<?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>Sharding on IT Comparison</title><link>https://comparison.metacog.co.kr/tags/sharding/</link><description>Recent content in Sharding on IT Comparison</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 06 Sep 2026 09:41:37 +0900</lastBuildDate><atom:link href="https://comparison.metacog.co.kr/tags/sharding/index.xml" rel="self" type="application/rss+xml"/><item><title>Range vs Hash Partitioning: Ordered Splits vs Scattered Buckets</title><link>https://comparison.metacog.co.kr/posts/2026-09-06-range-vs-hash-partitioning-ordered-splits-vs-scattered-bucke/</link><pubDate>Sun, 06 Sep 2026 09:41:37 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-09-06-range-vs-hash-partitioning-ordered-splits-vs-scattered-bucke/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Range and hash partitioning are two strategies for splitting a table&amp;rsquo;s rows across multiple partitions or nodes based on a partition key. Range partitioning assigns rows to &lt;strong class="kw"&gt;contiguous key intervals&lt;/strong&gt; (like date ranges), preserving order for efficient range scans but risking uneven load. Hash partitioning runs the key through a &lt;strong class="kw"&gt;hash function&lt;/strong&gt; to scatter rows evenly, trading away ordering for balanced, predictable distribution.&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="28" text-anchor="middle" font-size="16" font-weight="bold" style="fill:var(--primary)"&gt;RANGE PARTITIONING&lt;/text&gt;&lt;text x="480" y="28" text-anchor="middle" font-size="16" font-weight="bold" style="fill:var(--primary)"&gt;HASH PARTITIONING&lt;/text&gt;&lt;line x1="320" y1="10" x2="320" y2="345" style="stroke:var(--border)" stroke-width="1"/&gt;&lt;text x="160" y="45" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;incoming keys&lt;/text&gt;&lt;text x="480" y="45" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;incoming keys&lt;/text&gt;&lt;rect x="40" y="50" width="80" height="30" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="120" y="50" width="80" height="30" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="200" y="50" width="80" height="30" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="80" y="70" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;1-33&lt;/text&gt;&lt;text x="160" y="70" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;34-66&lt;/text&gt;&lt;text x="240" y="70" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;67-100&lt;/text&gt;&lt;rect x="360" y="50" width="80" height="30" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="440" y="50" width="80" height="30" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="520" y="50" width="80" height="30" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="400" y="70" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;1-33&lt;/text&gt;&lt;text x="480" y="70" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;34-66&lt;/text&gt;&lt;text x="560" y="70" text-anchor="middle" font-size="11" style="fill:var(--content)"&gt;67-100&lt;/text&gt;&lt;line x1="80" y1="80" x2="80" y2="168" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="160" y1="80" x2="160" y2="168" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="240" y1="80" x2="240" y2="168" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;line x1="400" y1="80" x2="560" y2="168" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="480" y1="80" x2="400" y2="168" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;line x1="560" y1="80" x2="480" y2="168" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="128" text-anchor="middle" font-size="10" style="fill:var(--secondary)"&gt;hash(key)&lt;/text&gt;&lt;rect x="50" y="170" width="60" height="40" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="130" y="170" width="60" height="40" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="210" y="170" width="60" height="40" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="80" y="194" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P1&lt;/text&gt;&lt;text x="160" y="194" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P2&lt;/text&gt;&lt;text x="240" y="194" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P3&lt;/text&gt;&lt;rect x="370" y="170" width="60" height="40" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="450" y="170" width="60" height="40" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="530" y="170" width="60" height="40" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="400" y="194" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P1&lt;/text&gt;&lt;text x="480" y="194" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P2&lt;/text&gt;&lt;text x="560" y="194" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;P3&lt;/text&gt;&lt;text x="160" y="240" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Ordered, contiguous ranges&lt;/text&gt;&lt;text x="480" y="240" text-anchor="middle" font-size="12" style="fill:var(--content)"&gt;Scattered, uniform spread&lt;/text&gt;&lt;text x="160" y="264" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Easy to extend: add a boundary&lt;/text&gt;&lt;text x="480" y="264" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Costly to resize: rehash keys&lt;/text&gt;&lt;text x="160" y="288" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Risk: skew on hot ranges&lt;/text&gt;&lt;text x="480" y="288" text-anchor="middle" font-size="11" style="fill:var(--secondary)"&gt;Risk: no range pruning&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;Range Partitioning&lt;/th&gt;
&lt;th&gt;Hash Partitioning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Partition key requirement&lt;/td&gt;
&lt;td&gt;Needs an orderable key with defined boundaries (dates, IDs)&lt;/td&gt;
&lt;td&gt;Any key works; only needs to be hashable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Row-to-partition mapping&lt;/td&gt;
&lt;td&gt;Explicit boundary rules assign rows to intervals&lt;/td&gt;
&lt;td&gt;Hash function output (often mod N) selects the bucket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data distribution&lt;/td&gt;
&lt;td&gt;Can be skewed if key values aren&amp;rsquo;t uniformly spread&lt;/td&gt;
&lt;td&gt;Near-uniform if the hash function distributes well&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Range/scan queries&lt;/td&gt;
&lt;td&gt;Prunes to only the partitions covering the range&lt;/td&gt;
&lt;td&gt;Must fan out and scan every partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Point/equality lookups&lt;/td&gt;
&lt;td&gt;Requires a boundary search to find the right partition&lt;/td&gt;
&lt;td&gt;Direct O(1) computation locates the partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adding or removing partitions&lt;/td&gt;
&lt;td&gt;Cheap: append or split a boundary at the edge&lt;/td&gt;
&lt;td&gt;Expensive: reshuffles most existing keys unless using consistent hashing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hotspot behavior&lt;/td&gt;
&lt;td&gt;Sequential writes (recent dates, auto-increment IDs) pile onto one partition&lt;/td&gt;
&lt;td&gt;Spreads writes evenly but destroys any physical data locality&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;Range partitioning preserves &lt;strong class="kw"&gt;order&lt;/strong&gt;, letting the query planner prune partitions; hash partitioning optimizes purely for &lt;strong class="kw"&gt;even distribution&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Growing the partition count is a cheap boundary edit in range partitioning but forces a &lt;strong class="kw"&gt;rehash&lt;/strong&gt; of most keys in hash partitioning&lt;/li&gt;
&lt;li&gt;Range schemes are exposed to &lt;strong class="kw"&gt;skew&lt;/strong&gt; when writes cluster in a narrow key window; hash schemes avoid this at the cost of locality&lt;/li&gt;
&lt;li&gt;Point lookups under hashing are a direct &lt;strong class="kw"&gt;hash computation&lt;/strong&gt;, while range lookups need a &lt;strong class="kw"&gt;boundary search&lt;/strong&gt; through ordered intervals&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;Range Partitioning&lt;/strong&gt;&lt;/p&gt;</description></item></channel></rss>