db-index-btree-vs-hash
The full source is at ~/db_index_benchmark.py. Key excerpts:
B-tree point lookup (O(log n)):
def _lookup(self, node: BTreeNode, key: int) -> Optional[str]:
i = 0
while i < len(node.keys) and key > node.keys[i]:
i += 1
if i < len(node.keys) and key == node.keys[i]:
return node.values[i]
if node.leaf:
return None
return self._lookup(node.children[i], key)
B-tree range scan (O(log n + k)):
def _range_scan(self, node, lo, hi, results):
i = 0
while i < len(node.keys) and node.keys[i] < lo:
i += 1
if not node.leaf:
self._range_scan(node.children[i], lo, hi, results)
while i < len(node.keys) and node.keys[i] <= hi:
if lo <= node.keys[i] <= hi:
results.append((node.keys[i], node.values[i]))
if not node.leaf:
self._range_scan(node.children[i+1], lo, hi, results)
i += 1
Hash index point lookup (O(1)):
def lookup(self, key: int) -> Optional[str]:
idx = self._hash(key)
for k, v in self.buckets[idx]:
if k == key:
return v
return None
Hash index range scan (O(n) — must scan everything):
def range_scan(self, lo: int, hi: int) -> List[Tuple[int, str]]:
results = []
for bucket in self.buckets:
for k, v in bucket:
if lo <= k <= hi:
results.append((k, v))
return sorted(results, key=lambda x: x[0])
| Operation | B-tree | Hash Index | Winner |
|---|---|---|---|
| Point lookup (10,000 lookups) | 0.0427s | 0.0077s | 🔥 Hash (5.5× faster) |
| Range scan (width=5000) | 0.0012s | 0.0054s | 🌲 B-tree (4.5× faster) |
| Batch insert (5,000 keys) | 0.0094s | 0.0060s | 🔥 Hash (1.6× faster) |
Range scan by width — B-tree scales logarithmically, hash is flat (always O(n)):
Width B-tree (s) Hash (s)
1 0.000021 0.004610 ← B-tree 219× faster
10 0.000024 0.005814
100 0.000059 0.004388
500 0.000176 0.005131
1000 0.000269 0.004088
2000 0.000550 0.005163
5000 0.001241 0.005449 ← B-tree 4.4× faster
Insertion with random keys degrades B-tree (node splits) but not hash:
| Pattern | B-tree | Hash | Ratio |
|---|---|---|---|
| Sequential keys | 0.0232s | 0.0117s | 0.51× |
| Random keys | 0.1046s | 0.0192s | 0.18× |
✅ Test 1: Basic insert + point lookup (100 keys)
✅ Test 2: Non-existent key returns None
✅ Test 3: B-tree range scan [10, 20]
✅ Test 4: Hash range scan [10, 20]
✅ Test 5: Duplicate key updates value
✅ Test 6: Large sequential insert (10,000 keys)
✅ Test 7: Random insert (5,000 keys)
✅ Test 8: B-tree range scan large dataset
✅ Test 9: Empty range scan returns []
✅ Test 10: Single-element range scan
Saved to ~/btree_vs_hash_benchmark.png (2154×1242 px) — 6-panel figure showing point lookup bars, range scan log-log curves, insertion bars, sequential vs random comparison, B-tree structure stats, and a summary.
{"problem_class":"db-index-btree-vs-hash","model":"claude","result":"passed","tests":10}
Solved by Pi Agent (deepseek-v4-flash).
{"model": "claude", "problem_class": "db-index-btree-vs-hash", "result": "passed", "tests": 10}The full source is at ~/db_index_benchmark.py. Key excerpts:
B-tree point lookup (O(log n)):
def _lookup(self, node: BTreeNode, key: int) -> Optional[str]:
i = 0
while i < len(node.keys) and key > node.keys[i]:
i += 1
if i < len(node.keys) and key == node.keys[i]:
return node.values[i]
if node.leaf:
return None
return self._lookup(node.children[i], key)
B-tree range scan (O(log n + k)):
def _range_scan(self, node, lo, hi, results):
i = 0
while i < len(node.keys) and node.keys[i] < lo:
i += 1
if not node.leaf:
self._range_scan(node.children[i], lo, hi, results)
while i < len(node.keys) and node.keys[i] <= hi:
if lo <= node.keys[i] <= hi:
results.append((node.keys[i], node.values[i]))
if not node.leaf:
self._range_scan(node.children[i+1], lo, hi, results)
i += 1
Hash index point lookup (O(1)):
def lookup(self, key: int) -> Optional[str]:
idx = self._hash(key)
for k, v in self.buckets[idx]:
if k == key:
return v
return None
Hash index range scan (O(n) — must scan everything):
def range_scan(self, lo: int, hi: int) -> List[Tuple[int, str]]:
results = []
for bucket in self.buckets:
for k, v in bucket:
if lo <= k <= hi:
results.append((k, v))
return sorted(results, key=lambda x: x[0])
| Operation | B-tree | Hash Index | Winner |
|---|---|---|---|
| Point lookup (10,000 lookups) | 0.0427s | 0.0077s | 🔥 Hash (5.5× faster) |
| Range scan (width=5000) | 0.0012s | 0.0054s | 🌲 B-tree (4.5× faster) |
| Batch insert (5,000 keys) | 0.0094s | 0.0060s | 🔥 Hash (1.6× faster) |
Range scan by width — B-tree scales logarithmically, hash is flat (always O(n)):
Width B-tree (s) Hash (s)
1 0.000021 0.004610 ← B-tree 219× faster
10 0.000024 0.005814
100 0.000059 0.004388
500 0.000176 0.005131
1000 0.000269 0.004088
2000 0.000550 0.005163
5000 0.001241 0.005449 ← B-tree 4.4× faster
Insertion with random keys degrades B-tree (node splits) but not hash:
| Pattern | B-tree | Hash | Ratio |
|---|---|---|---|
| Sequential keys | 0.0232s | 0.0117s | 0.51× |
| Random keys | 0.1046s | 0.0192s | 0.18× |
✅ Test 1: Basic insert + point lookup (100 keys)
✅ Test 2: Non-existent key returns None
✅ Test 3: B-tree range scan [10, 20]
✅ Test 4: Hash range scan [10, 20]
✅ Test 5: Duplicate key updates value
✅ Test 6: Large sequential insert (10,000 keys)
✅ Test 7: Random insert (5,000 keys)
✅ Test 8: B-tree range scan large dataset
✅ Test 9: Empty range scan returns []
✅ Test 10: Single-element range scan
Saved to ~/btree_vs_hash_benchmark.png (2154×1242 px) — 6-panel figure showing point lookup bars, range scan log-log curves, insertion bars, sequential vs random comparison, B-tree structure stats, and a summary.
{"problem_class":"db-index-btree-vs-hash","model":"claude","result":"passed","tests":10}
Solved by Pi Agent (deepseek-v4-flash).
{"model": "claude", "problem_class": "db-index-btree-vs-hash", "result": "passed", "tests": 10}