๐ Dense Index
A Dense Index has one index entry for every record in the database file.
It directly maps each search key to a specific data record.
โ Characteristics:
Every record has a corresponding index entry.
Fast for searching any value.
Uses more storage.
๐ง Example:
Consider a data table:
RollNo | Name |
|---|---|
101 | A |
102 | B |
103 | C |
Dense index would be:
[101] โ Record 1
[102] โ Record 2
[103] โ Record 3Each row is indexed.
๐ Sparse Index
A Sparse Index has index entries for only some records โ typically one per block/page.
It assumes data is sorted on the indexed column.
โ Characteristics:
Not every record is indexed.
Requires less space.
Slower than dense index for point lookups (needs block scanning).
๐ง Example:
Suppose records are stored across disk blocks:
Block 1: 101, 102
Block 2: 103, 104
Block 3: 105, 106
Sparse index:
[101] โ Block 1
[103] โ Block 2
[105] โ Block 3Only first record of each block is indexed.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dense vs Sparse Index โ Try It Yourself</title>
<style>
.infographic-densesparse {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #16a34a;
--good-soft: #dcfce7;
--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);
padding: 2.5rem 1.5rem 2rem;
max-width: 980px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-densesparse[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;
}
.infographic-densesparse * { box-sizing: border-box; }
.ds-head { text-align: center; margin-bottom: 0.25rem; }
.ds-head h2 {
font-family: var(--display-font);
font-size: 1.95rem;
margin: 0 0 0.5rem;
}
.ds-head p {
color: var(--ink-soft);
font-size: 1rem;
margin: 0 auto;
max-width: 600px;
line-height: 1.55;
}
.ds-query {
margin-top: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
gap: 0.6rem;
flex-wrap: wrap;
}
.ds-query-text {
font-family: var(--mono-font);
font-size: 0.9rem;
background: var(--paper-alt);
border: 1px solid var(--line);
border-radius: 8px;
padding: 0.6rem 0.9rem;
}
.ds-query select {
font: inherit;
font-family: var(--mono-font);
font-size: 0.9rem;
padding: 0.5rem 0.6rem;
border: 1px solid var(--line);
border-radius: 6px;
background: var(--paper);
color: var(--accent);
font-weight: 700;
}
.ds-blocks {
display: flex;
gap: 0.9rem;
justify-content: center;
margin-top: 1.5rem;
flex-wrap: wrap;
}
.ds-block {
background: var(--paper-alt);
border: 2px solid var(--line);
border-radius: 8px;
padding: 0.7rem;
min-width: 130px;
transition: border-color 0.2s;
}
.ds-block.is-active-block { border-color: var(--accent); }
.ds-block-label { font-size: 0.7rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 0.4rem; text-align: center; }
.ds-record {
font-family: var(--mono-font);
font-size: 0.82rem;
background: var(--paper);
border: 1px solid var(--line);
border-radius: 5px;
padding: 0.3rem 0.5rem;
margin-bottom: 0.3rem;
transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.ds-record:last-child { margin-bottom: 0; }
.ds-record.is-checking { background: var(--accent-soft); border-color: var(--accent); }
.ds-record.is-match { background: var(--good-soft); color: var(--good); border-color: var(--good); font-weight: 700; }
.ds-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-top: 1.75rem; min-width: 0; }
@media (max-width: 680px) { .ds-panels { grid-template-columns: 1fr; } }
.ds-panel { background: var(--paper-alt); border: 1px solid var(--line); border-radius: 10px; padding: 1.1rem; min-width: 0; }
.ds-panel-title { font-family: var(--display-font); font-size: 1rem; margin: 0 0 0.3rem; }
.ds-panel-sub { font-size: 0.78rem; color: var(--ink-soft); margin: 0 0 0.75rem; }
.ds-entry-list { display: flex; flex-direction: column; gap: 0.35rem; margin-bottom: 0.9rem; }
.ds-entry {
font-family: var(--mono-font);
font-size: 0.8rem;
background: var(--paper);
border: 1px solid var(--line);
border-radius: 6px;
padding: 0.4rem 0.6rem;
transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.ds-entry.is-checking { background: var(--accent-soft); border-color: var(--accent); }
.ds-entry.is-match { background: var(--good-soft); color: var(--good); border-color: var(--good); font-weight: 700; }
.ds-size-bar-row { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }
.ds-size-bar-track { flex: 1; height: 10px; background: var(--paper); border: 1px solid var(--line); border-radius: 999px; overflow: hidden; }
.ds-size-bar-fill { height: 100%; background: var(--accent); }
.ds-size-label { font-size: 0.75rem; color: var(--ink-soft); white-space: nowrap; }
.ds-btn {
font: inherit;
font-size: 0.85rem;
background: var(--accent);
color: #fff;
border: none;
border-radius: 7px;
padding: 0.55rem 1rem;
cursor: pointer;
width: 100%;
}
.ds-btn:hover { opacity: 0.9; }
.ds-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.ds-score { margin-top: 0.7rem; font-size: 0.82rem; color: var(--ink-soft); }
.ds-score b { color: var(--ink); }
.ds-controls-row { display: flex; justify-content: center; margin-top: 1.25rem; }
.ds-reset-btn {
font: inherit;
font-size: 0.82rem;
background: var(--paper);
border: 1px solid var(--line);
border-radius: 7px;
padding: 0.45rem 0.9rem;
cursor: pointer;
color: var(--ink);
}
.ds-reset-btn:hover { border-color: var(--accent); }
.ds-log-scroll { overflow-x: auto; margin-top: 1.25rem; }
.ds-log {
background: var(--ink);
color: #d4e2ff;
border-radius: 8px;
padding: 0.75rem 0.9rem;
font-family: var(--mono-font);
font-size: 0.78rem;
line-height: 1.65;
min-height: 2rem;
}
.infographic-densesparse[data-theme="dark"] .ds-log { background: #05070a; }
.ds-log-line { opacity: 0; animation: ds-line-in 0.25s ease forwards; }
@keyframes ds-line-in { to { opacity: 1; } }
.ds-log-placeholder { color: #7c8aa8; font-style: italic; }
@media (prefers-reduced-motion: reduce) {
.infographic-densesparse *, .infographic-densesparse *::before, .infographic-densesparse *::after {
transition-duration: 0.001ms !important;
animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-densesparse" id="densesparse">
<div class="ds-head">
<h2>Dense vs Sparse Index โ Try It Yourself</h2>
<p>Records are stored across 3 disk blocks. Pick a RollNo and run the same search both ways.</p>
</div>
<div class="ds-query">
<span class="ds-query-text">Find RollNo =</span>
<select id="dsSelect"></select>
</div>
<div class="ds-blocks" id="dsBlocks"></div>
<div class="ds-panels">
<div class="ds-panel">
<p class="ds-panel-title">Dense Index</p>
<p class="ds-panel-sub">One entry per record</p>
<div class="ds-entry-list" id="dsDenseList"></div>
<div class="ds-size-bar-row">
<div class="ds-size-bar-track"><div class="ds-size-bar-fill" style="width:100%"></div></div>
<span class="ds-size-label">6 entries</span>
</div>
<button class="ds-btn" id="dsRunDense" type="button">Search with Dense Index</button>
<div class="ds-score" id="dsDenseScore"></div>
</div>
<div class="ds-panel">
<p class="ds-panel-title">Sparse Index</p>
<p class="ds-panel-sub">One entry per block</p>
<div class="ds-entry-list" id="dsSparseList"></div>
<div class="ds-size-bar-row">
<div class="ds-size-bar-track"><div class="ds-size-bar-fill" style="width:50%"></div></div>
<span class="ds-size-label">3 entries</span>
</div>
<button class="ds-btn" id="dsRunSparse" type="button">Search with Sparse Index</button>
<div class="ds-score" id="dsSparseScore"></div>
</div>
</div>
<div class="ds-controls-row">
<button class="ds-reset-btn" id="dsReset" type="button">Reset</button>
</div>
<div class="ds-log-scroll">
<div class="ds-log" id="dsLog"><span class="ds-log-placeholder">Run a search above to see it happen step by step...</span></div>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('densesparse');
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');
})();
(function () {
const blocks = [
{ name: 'Block 1', records: [{ rollNo: 101, name: 'A' }, { rollNo: 102, name: 'B' }] },
{ name: 'Block 2', records: [{ rollNo: 103, name: 'C' }, { rollNo: 104, name: 'D' }] },
{ name: 'Block 3', records: [{ rollNo: 105, name: 'E' }, { rollNo: 106, name: 'F' }] }
];
const allRecords = blocks.flatMap((b, bi) => b.records.map((r, ri) => ({ ...r, blockIndex: bi, recNum: bi * 2 + ri + 1 })));
const sparseEntries = blocks.map((b, bi) => ({ rollNo: b.records[0].rollNo, blockIndex: bi }));
const blocksEl = document.getElementById('dsBlocks');
const denseList = document.getElementById('dsDenseList');
const sparseList = document.getElementById('dsSparseList');
const select = document.getElementById('dsSelect');
const log = document.getElementById('dsLog');
const denseScore = document.getElementById('dsDenseScore');
const sparseScore = document.getElementById('dsSparseScore');
const runDenseBtn = document.getElementById('dsRunDense');
const runSparseBtn = document.getElementById('dsRunSparse');
function renderBlocks() {
blocksEl.innerHTML = blocks.map((b, bi) =>
'<div class="ds-block" data-block="' + bi + '">' +
'<div class="ds-block-label">' + b.name + '</div>' +
b.records.map(r => '<div class="ds-record" data-roll="' + r.rollNo + '">[' + r.rollNo + '] ' + r.name + '</div>').join('') +
'</div>'
).join('');
}
function renderDenseList() {
denseList.innerHTML = allRecords.map(r =>
'<div class="ds-entry" data-roll="' + r.rollNo + '">[' + r.rollNo + '] โ Record ' + r.recNum + '</div>'
).join('');
}
function renderSparseList() {
sparseList.innerHTML = sparseEntries.map((e, i) =>
'<div class="ds-entry" data-idx="' + i + '">[' + e.rollNo + '] โ Block ' + (e.blockIndex + 1) + '</div>'
).join('');
}
function fillSelect() {
select.innerHTML = allRecords.map(r => '<option value="' + r.rollNo + '">' + r.rollNo + '</option>').join('');
select.value = '104';
}
function clearLog() { log.innerHTML = ''; }
function appendLog(text) {
if (log.querySelector('.ds-log-placeholder')) log.innerHTML = '';
const line = document.createElement('div');
line.className = 'ds-log-line';
line.textContent = text;
log.appendChild(line);
}
function clearHighlights() {
document.querySelectorAll('.ds-record').forEach(el => el.classList.remove('is-checking', 'is-match'));
document.querySelectorAll('.ds-block').forEach(el => el.classList.remove('is-active-block'));
document.querySelectorAll('#dsDenseList .ds-entry').forEach(el => el.classList.remove('is-checking', 'is-match'));
document.querySelectorAll('#dsSparseList .ds-entry').forEach(el => el.classList.remove('is-checking', 'is-match'));
}
function setButtons(disabled) {
runDenseBtn.disabled = disabled;
runSparseBtn.disabled = disabled;
}
runDenseBtn.addEventListener('click', () => {
clearHighlights();
clearLog();
setButtons(true);
const target = Number(select.value);
const entry = denseList.querySelector('.ds-entry[data-roll="' + target + '"]');
entry.classList.add('is-checking');
appendLog('Dense index: look up [' + target + '] directly...');
setTimeout(() => {
entry.classList.remove('is-checking');
entry.classList.add('is-match');
const rec = allRecords.find(r => r.rollNo === target);
const recEl = document.querySelector('.ds-record[data-roll="' + target + '"]');
recEl.classList.add('is-match');
document.querySelector('.ds-block[data-block="' + rec.blockIndex + '"]').classList.add('is-active-block');
appendLog('โ Found directly: Record ' + rec.recNum + '. 1 lookup, no scanning.');
denseScore.innerHTML = '<b>1</b> index lookup, <b>0</b> extra scanning';
setButtons(false);
}, 500);
});
runSparseBtn.addEventListener('click', () => {
clearHighlights();
clearLog();
setButtons(true);
const target = Number(select.value);
let bestBlock = 0;
let i = 0;
function checkEntry() {
if (i >= sparseEntries.length) { afterFindBlock(); return; }
const e = sparseEntries[i];
document.querySelectorAll('#dsSparseList .ds-entry').forEach(el => el.classList.remove('is-checking'));
const el = sparseList.querySelector('.ds-entry[data-idx="' + i + '"]');
el.classList.add('is-checking');
if (e.rollNo <= target) {
bestBlock = e.blockIndex;
appendLog('Sparse index: [' + e.rollNo + '] โค ' + target + ' โ candidate block ' + (e.blockIndex + 1));
i++;
setTimeout(checkEntry, 420);
} else {
appendLog('Sparse index: [' + e.rollNo + '] > ' + target + ' โ stop, use block ' + (bestBlock + 1));
el.classList.remove('is-checking');
afterFindBlock();
}
}
function afterFindBlock() {
const bestEl = sparseList.querySelector('.ds-entry[data-idx="' + sparseEntries.findIndex(e => e.blockIndex === bestBlock) + '"]');
bestEl.classList.add('is-match');
document.querySelector('.ds-block[data-block="' + bestBlock + '"]').classList.add('is-active-block');
const recordsInBlock = blocks[bestBlock].records;
let j = 0;
let scans = 0;
function scanRecord() {
if (j >= recordsInBlock.length) { setButtons(false); return; }
const r = recordsInBlock[j];
const recEl = document.querySelector('.ds-record[data-roll="' + r.rollNo + '"]');
document.querySelectorAll('.ds-record').forEach(el => el.classList.remove('is-checking'));
recEl.classList.add('is-checking');
scans++;
appendLog('Scanning inside block ' + (bestBlock + 1) + ': RollNo ' + r.rollNo + (r.rollNo === target ? ' โ match!' : ' โ ' + target));
if (r.rollNo === target) {
recEl.classList.remove('is-checking');
recEl.classList.add('is-match');
sparseScore.innerHTML = '<b>' + (i + 1) + '</b> index compare(s), <b>' + scans + '</b> record(s) scanned in block';
setButtons(false);
return;
}
j++;
setTimeout(scanRecord, 420);
}
setTimeout(scanRecord, 420);
}
checkEntry();
});
document.getElementById('dsReset').addEventListener('click', () => {
clearHighlights();
clearLog();
log.innerHTML = '<span class="ds-log-placeholder">Run a search above to see it happen step by step...</span>';
denseScore.innerHTML = '';
sparseScore.innerHTML = '';
setButtons(false);
});
renderBlocks();
renderDenseList();
renderSparseList();
fillSelect();
})();
</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!');
});๐ Comparison Table: Dense vs Sparse Index
Feature | Dense Index | Sparse Index |
|---|---|---|
๐ Index Entries | One per record | One per data block/page |
๐ Storage Overhead | High (more index entries) | Low (fewer entries) |
๐ Search Speed | Fastest (direct access to records) | Slower (may require scanning in block) |
๐งน Maintenance | More expensive (due to many entries) | Easier to maintain |
๐ฆ Space Requirement | Larger index file | Smaller index file |
๐ Ideal for | Small datasets or frequent exact lookups | Large datasets with sorted data |
๐ง Summary Analogy:
Think of dense index like a dictionary where every word is listed.
Think of sparse index like a chapter summary โ it tells you where sections start, but not every detail.
๐งฎ Bonus Tip:
Sparse index works only on ordered data.
Often, a sparse outer index is used on top of dense inner indexes for multi-level indexing (used in large DBs).