Partitioning is the process of dividing a large database into smaller, manageable pieces called partitions. Each partition holds a subset of the total data, and they can be stored on the same server or multiple servers.
👉 When we scale out (also called horizontal scaling), we spread these partitions across multiple machines to handle:
More data
More concurrent users
Higher throughput
🔸 Types of Partitioning
Type | Description | Example |
|---|---|---|
🔹 Horizontal Partitioning (Sharding) | Rows of a table are divided across partitions. Each shard has a different subset of rows. | Users with ID 1–1000 in one partition, 1001–2000 in another |
🔸 Vertical Partitioning | Columns are divided across tables (or servers). | Store frequently accessed columns separately from rarely accessed ones |
🔹 Range Partitioning | Data is partitioned based on a range of values. | Orders from Jan–Mar in one partition, Apr–Jun in another |
🔸 Hash Partitioning | A hash function determines which partition data goes to. |
|
🔹 List Partitioning | Based on predefined values (categories, regions, etc.) | Country = ‘India’ in one, ‘USA’ in another |
🔸 Why Use Partitioning for Scaling Out?
Benefit | Explanation |
|---|---|
✅ Improved Performance | Each query deals with smaller datasets |
✅ Parallel Processing | Different partitions can be queried in parallel |
✅ High Availability | Failures in one partition don’t affect the others |
✅ Easy Maintenance | You can back up or archive partitions independently |
✅ Scalability | Easily add new servers and move partitions around |
🔸 Real-World Example – MongoDB Sharding (Horizontal Partitioning)
MongoDB uses shards (horizontal partitions) to scale out the database:
# Each shard stores part of the data
Shard 1: Users 1–100000
Shard 2: Users 100001–200000
Shard 3: Users 200001–300000MongoDB decides which shard to use based on a shard key (e.g., user ID).
🔸 SQL Example – Range Partitioning
CREATE TABLE Orders (
OrderID INT,
OrderDate DATE,
...
)
PARTITION BY RANGE (YEAR(OrderDate)) (
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024)
);This example partitions orders by year, helping queries on a specific year to run faster.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sharding & Range Partitioning — Try It Yourself</title>
<style>
.infographic-partitioning {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #16a34a;
--good-soft: #dcfce7;
--bad: #dc2626;
--bad-soft: #fee2e2;
--on-accent: #ffffff;
--display-font: Georgia, 'Iowan Old Style', serif;
--body-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--mono-font: 'SF Mono', Consolas, monospace;
background: var(--paper);
color: var(--ink);
font-family: var(--body-font);
max-width: 840px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-partitioning[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4ade80;
--good-soft: #123420;
--bad: #f87171;
--bad-soft: #3a1414;
--on-accent: #101418;
}
.infographic-partitioning * { box-sizing: border-box; }
.pt-head { text-align: center; margin-bottom: 0.25rem; }
.pt-head h2 { font-family: var(--display-font); font-size: 1.85rem; margin: 0 0 0.5rem; }
.pt-head p { color: var(--ink-soft); font-size: 0.95rem; margin: 0 auto; max-width: 600px; line-height: 1.55; }
.pt-tabs { display: flex; gap: 0.5rem; margin-top: 1.5rem; flex-wrap: wrap; justify-content: center; }
.pt-tab-btn {
font: inherit; font-size: 0.85rem; background: var(--paper-alt); color: var(--ink-soft);
border: 1px solid var(--line); border-radius: 999px; padding: 0.5rem 1rem; cursor: pointer;
}
.pt-tab-btn.is-active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.pt-panel { display: none; background: var(--paper-alt); border: 1px solid var(--line); border-radius: 10px; padding: 1.25rem; margin-top: 1rem; }
.pt-panel.is-active { display: block; animation: pt-fade-in 0.35s ease; }
@keyframes pt-fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.pt-panel-title { font-family: var(--display-font); font-size: 1.15rem; margin: 0 0 0.4rem; }
.pt-panel-desc { font-size: 0.85rem; color: var(--ink-soft); line-height: 1.5; margin: 0 0 0.9rem; }
.pt-code-scroll { overflow-x: auto; margin-bottom: 1rem; }
.pt-code {
background: var(--ink); color: #d4e2ff; border-radius: 8px; padding: 0.75rem 0.95rem;
font-family: var(--mono-font); font-size: 0.76rem; line-height: 1.55; white-space: pre;
}
.infographic-partitioning[data-theme="dark"] .pt-code { background: #05070a; }
.pt-kw { color: #9cc5ff; } .pt-str { color: #f8d980; } .pt-num { color: #4ade80; } .pt-cm { color: #7c8aa8; }
.pt-diagram-scroll { overflow-x: auto; }
.pt-diagram-scroll svg { width: 100%; height: auto; display: block; min-width: 400px; }
.pt-shard-box { fill: var(--paper); stroke: var(--accent); stroke-width: 2; transition: fill 0.4s, stroke 0.4s, opacity 0.4s; }
.pt-shard-box.is-target { fill: var(--good-soft); stroke: var(--good); }
.pt-shard-box.is-dimmed { opacity: 0.35; }
.pt-shard-text { font-size: 12px; font-weight: 700; font-family: var(--body-font); text-anchor: middle; fill: var(--ink); }
.pt-shard-range { font-size: 10px; font-family: var(--mono-font); text-anchor: middle; fill: var(--ink-soft); }
.pt-beam { stroke: var(--accent); stroke-width: 3; fill: none; opacity: 0; marker-end: url(#ptArrow); }
.pt-beam.is-active { opacity: 1; }
.pt-userid-row { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: center; margin-top: 1rem; }
.pt-userid-btn {
font: inherit; font-size: 0.8rem; font-family: var(--mono-font); background: var(--paper); color: var(--ink);
border: 1px solid var(--line); border-radius: 7px; padding: 0.45rem 0.7rem; cursor: pointer;
}
.pt-userid-btn:hover { border-color: var(--accent); }
.pt-userid-btn.is-selected { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.pt-partition-box { fill: none; stroke: var(--line); stroke-width: 1.5; transition: stroke 0.4s; }
.pt-partition-box.is-scanned { stroke: var(--accent); stroke-width: 2.5; }
.pt-partition-box.is-skipped { stroke: var(--good); stroke-dasharray: 5 4; }
.pt-row-rect { fill: var(--paper); stroke: var(--line); stroke-width: 1; transition: fill 0.4s, opacity 0.4s; }
.pt-row-rect.is-scanned { fill: var(--accent-soft); }
.pt-row-rect.is-skipped { opacity: 0.3; }
.pt-cell-text { font-size: 9px; font-family: var(--mono-font); text-anchor: middle; fill: var(--ink); }
.pt-partition-label { font-size: 10px; font-weight: 700; font-family: var(--body-font); text-anchor: middle; fill: var(--ink-soft); }
.pt-run-row { display: flex; justify-content: center; gap: 0.6rem; margin-top: 1.1rem; flex-wrap: wrap; }
.pt-run-btn {
font: inherit; font-size: 0.83rem; background: var(--accent); color: var(--on-accent);
border: none; border-radius: 7px; padding: 0.55rem 1rem; cursor: pointer;
}
.pt-run-btn:hover { opacity: 0.9; }
.pt-run-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.pt-run-btn.is-secondary { background: var(--paper); color: var(--ink); border: 1px solid var(--line); }
.pt-scoreboard { display: flex; justify-content: center; gap: 2rem; margin-top: 1rem; flex-wrap: wrap; }
.pt-score-item { text-align: center; }
.pt-score-label { font-size: 0.72rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; }
.pt-score-value { font-size: 1.3rem; font-weight: 700; color: var(--accent); font-family: var(--mono-font); }
.pt-msg { margin-top: 0.9rem; padding: 0.6rem 0.85rem; border-radius: 8px; font-size: 0.83rem; line-height: 1.5; display: none; background: var(--good-soft); color: var(--good); }
.pt-msg.is-visible { display: block; }
@media (prefers-reduced-motion: reduce) {
.infographic-partitioning *, .infographic-partitioning *::before, .infographic-partitioning *::after {
transition-duration: 0.001ms !important; animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-partitioning" id="partitioning">
<div class="pt-head">
<h2>Sharding & Range Partitioning</h2>
<p>Both split a huge table into smaller pieces — the difference is which piece your query even has to touch.</p>
</div>
<div class="pt-tabs">
<button class="pt-tab-btn is-active" data-tab="shard" type="button">🍃 MongoDB Sharding</button>
<button class="pt-tab-btn" data-tab="range" type="button">📅 SQL Range Partitioning</button>
</div>
<!-- TAB 1: Sharding -->
<div class="pt-panel is-active" id="panel-shard">
<p class="pt-panel-title">Horizontal Partitioning (Sharding)</p>
<p class="pt-panel-desc">MongoDB picks a shard using the shard key — here, user ID — and routes the query to that one shard only.</p>
<div class="pt-code-scroll">
<div class="pt-code"><span class="pt-cm"># Each shard stores part of the data</span>
Shard 1: Users <span class="pt-num">1</span>–<span class="pt-num">100000</span>
Shard 2: Users <span class="pt-num">100001</span>–<span class="pt-num">200000</span>
Shard 3: Users <span class="pt-num">200001</span>–<span class="pt-num">300000</span></div>
</div>
<div class="pt-diagram-scroll">
<svg viewBox="0 0 560 170" id="shardSvg"></svg>
</div>
<p style="text-align:center; font-size:0.8rem; color:var(--ink-soft); margin: 0.9rem 0 0.4rem;">Pick a user ID to query:</p>
<div class="pt-userid-row" id="userIdRow"></div>
<p class="pt-msg" id="shardMsg"></p>
</div>
<!-- TAB 2: Range Partitioning -->
<div class="pt-panel" id="panel-range">
<p class="pt-panel-title">SQL Range Partitioning</p>
<p class="pt-panel-desc">Orders are split by year at the storage level. A query for one year can skip every other partition entirely.</p>
<div class="pt-code-scroll">
<div class="pt-code"><span class="pt-kw">CREATE TABLE</span> Orders (
OrderID <span class="pt-kw">INT</span>,
OrderDate <span class="pt-kw">DATE</span>,
...
)
<span class="pt-kw">PARTITION BY RANGE</span> (<span class="pt-kw">YEAR</span>(OrderDate)) (
<span class="pt-kw">PARTITION</span> p2022 <span class="pt-kw">VALUES LESS THAN</span> (<span class="pt-num">2023</span>),
<span class="pt-kw">PARTITION</span> p2023 <span class="pt-kw">VALUES LESS THAN</span> (<span class="pt-num">2024</span>)
);</div>
</div>
<div class="pt-diagram-scroll">
<svg viewBox="0 0 560 200" id="rangeSvg"></svg>
</div>
<div class="pt-run-row">
<button class="pt-run-btn" id="prunedBtn" type="button">▶ Run: WHERE YEAR(OrderDate) = 2023 (partitioned)</button>
<button class="pt-run-btn is-secondary" id="fullScanBtn" type="button">▶ Run same query (no partitioning)</button>
<button class="pt-run-btn is-secondary" id="rangeReset" type="button">↺ Reset</button>
</div>
<div class="pt-scoreboard">
<div class="pt-score-item"><div class="pt-score-label">Partitioned scan</div><div class="pt-score-value" id="prunedScore">–</div></div>
<div class="pt-score-item"><div class="pt-score-label">Full table scan</div><div class="pt-score-value" id="fullScore">–</div></div>
</div>
<p class="pt-msg" id="rangeMsg"></p>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('partitioning');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
/* tabs */
(function () {
document.querySelectorAll('.pt-tab-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.pt-tab-btn').forEach(b => b.classList.remove('is-active'));
document.querySelectorAll('.pt-panel').forEach(p => p.classList.remove('is-active'));
btn.classList.add('is-active');
document.getElementById('panel-' + btn.dataset.tab).classList.add('is-active');
});
});
})();
/* TAB 1: Sharding */
(function () {
const svg = document.getElementById('shardSvg');
const shards = [
{ key: 1, x: 90, label: 'Shard 1', range: '1 – 100000', lo: 1, hi: 100000 },
{ key: 2, x: 280, label: 'Shard 2', range: '100001 – 200000', lo: 100001, hi: 200000 },
{ key: 3, x: 470, label: 'Shard 3', range: '200001 – 300000', lo: 200001, hi: 300000 }
];
const userIds = [42, 55000, 99999, 100001, 175000, 250000, 300000];
function renderBase() {
let html = '<defs><marker id="ptArrow" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 z" fill="var(--accent)"></path></marker></defs>';
html += '<circle cx="30" cy="150" r="16" fill="var(--paper)" stroke="var(--accent)" stroke-width="2"></circle><text class="pt-shard-text" x="30" y="155" font-size="14">Q</text>';
shards.forEach(s => {
html += '<rect class="pt-shard-box" id="shard-' + s.key + '" x="' + (s.x - 65) + '" y="40" width="130" height="70" rx="8"></rect>';
html += '<text class="pt-shard-text" x="' + s.x + '" y="70">' + s.label + '</text>';
html += '<text class="pt-shard-range" x="' + s.x + '" y="88">' + s.range + '</text>';
html += '<path class="pt-beam" id="beam-' + s.key + '" d="M50,150 L' + (s.x) + ',115" ></path>';
});
svg.innerHTML = html;
}
renderBase();
const row = document.getElementById('userIdRow');
userIds.forEach(id => {
const btn = document.createElement('button');
btn.className = 'pt-userid-btn';
btn.type = 'button';
btn.textContent = 'User #' + id;
btn.addEventListener('click', () => {
document.querySelectorAll('.pt-userid-btn').forEach(b => b.classList.remove('is-selected'));
btn.classList.add('is-selected');
const target = shards.find(s => id >= s.lo && id <= s.hi);
shards.forEach(s => {
const box = document.getElementById('shard-' + s.key);
const beam = document.getElementById('beam-' + s.key);
box.classList.remove('is-target', 'is-dimmed');
beam.classList.remove('is-active');
if (s.key === target.key) { box.classList.add('is-target'); beam.classList.add('is-active'); }
else { box.classList.add('is-dimmed'); }
});
document.getElementById('shardMsg').textContent = '✔️ User #' + id + ' → routed to ' + target.label + ' (' + target.range + '). The other two shards are never touched.';
document.getElementById('shardMsg').classList.add('is-visible');
});
row.appendChild(btn);
});
})();
/* TAB 2: Range partitioning */
(function () {
const svg = document.getElementById('rangeSvg');
const p2022 = [{ id: 501, date: '2022-03-11' }, { id: 502, date: '2022-07-02' }, { id: 503, date: '2022-11-20' }];
const p2023 = [{ id: 601, date: '2023-01-15' }, { id: 602, date: '2023-05-09' }, { id: 603, date: '2023-09-30' }];
function renderPartitions() {
let html = '';
html += '<text class="pt-partition-label" x="140" y="16">p2022</text>';
html += '<rect class="pt-partition-box" id="box-p2022" x="20" y="24" width="240" height="150" rx="8"></rect>';
p2022.forEach((r, i) => {
const y = 40 + i * 45;
html += '<rect class="pt-row-rect" id="row-2022-' + r.id + '" x="35" y="' + y + '" width="210" height="32" rx="4"></rect>';
html += '<text class="pt-cell-text" x="140" y="' + (y + 20) + '">OrderID ' + r.id + ' | ' + r.date + '</text>';
});
html += '<text class="pt-partition-label" x="420" y="16">p2023</text>';
html += '<rect class="pt-partition-box" id="box-p2023" x="300" y="24" width="240" height="150" rx="8"></rect>';
p2023.forEach((r, i) => {
const y = 40 + i * 45;
html += '<rect class="pt-row-rect" id="row-2023-' + r.id + '" x="315" y="' + y + '" width="210" height="32" rx="4"></rect>';
html += '<text class="pt-cell-text" x="420" y="' + (y + 20) + '">OrderID ' + r.id + ' | ' + r.date + '</text>';
});
svg.innerHTML = html;
}
renderPartitions();
function clearScan() {
document.querySelectorAll('.pt-row-rect').forEach(el => el.classList.remove('is-scanned', 'is-skipped'));
document.getElementById('box-p2022').classList.remove('is-scanned', 'is-skipped');
document.getElementById('box-p2023').classList.remove('is-scanned', 'is-skipped');
}
document.getElementById('prunedBtn').addEventListener('click', function () {
clearScan();
document.getElementById('box-p2022').classList.add('is-skipped');
document.getElementById('box-p2023').classList.add('is-scanned');
p2022.forEach(r => document.getElementById('row-2022-' + r.id).classList.add('is-skipped'));
p2023.forEach(r => document.getElementById('row-2023-' + r.id).classList.add('is-scanned'));
document.getElementById('prunedScore').textContent = '3 rows read';
document.getElementById('rangeMsg').textContent = '✔️ p2022 is skipped entirely (partition pruning) — only the 3 rows inside p2023 are actually read.';
document.getElementById('rangeMsg').classList.add('is-visible');
});
document.getElementById('fullScanBtn').addEventListener('click', function () {
clearScan();
document.getElementById('box-p2022').classList.add('is-scanned');
document.getElementById('box-p2023').classList.add('is-scanned');
p2022.forEach(r => document.getElementById('row-2022-' + r.id).classList.add('is-scanned'));
p2023.forEach(r => document.getElementById('row-2023-' + r.id).classList.add('is-scanned'));
document.getElementById('fullScore').textContent = '6 rows read';
document.getElementById('rangeMsg').textContent = '⚠️ Without partitioning, the same query has no shortcut — every row in the table gets checked, including all of p2022, just to throw most of it away.';
document.getElementById('rangeMsg').classList.add('is-visible');
});
document.getElementById('rangeReset').addEventListener('click', () => {
clearScan();
document.getElementById('prunedScore').textContent = '–';
document.getElementById('fullScore').textContent = '–';
document.getElementById('rangeMsg').classList.remove('is-visible');
});
})();
</script>
</body>
</html>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});🔸 Partitioning vs Sharding
Aspect | Partitioning | Sharding (Horizontal Partitioning) |
|---|---|---|
Scope | General term | Specific type of partitioning |
Goal | Manageability & performance | Scalability across distributed systems |
Distribution | Can be on single or multiple servers | Always across multiple servers |
🔚 Summary
Partitioning helps divide and conquer large datasets.
It's essential for scaling out a database system.
Horizontal partitioning (sharding) is the most common method for scaling out.
Popular in NoSQL (MongoDB, Cassandra) and now widely supported in SQL databases (PostgreSQL, MySQL, etc.).