---
include_toc: true
gitea: none
---
# paulDB đŠđłïžâđ
> **Eine eigene HTAP-Datenbank in Rust.**
> Row- *und* Column-Storage in *einer* In-Memory-Engine, verbunden durch ein
> Delta-Merge-Konzept nach dem Vorbild von SAP HANA.
> Gebaut, um zu **verstehen** â nicht nur zu benutzen.
`Status: đ± Vision-Phase` · `Sprache: Rust` · `Modell: In-Memory HTAP` · `Lizenz: MIT`
---
## Was ist paulDB?
paulDB ist mein Versuch, eine Datenbank von Grund auf selbst zu schreiben â in Rust.
Nicht, weil die Welt noch eine Datenbank braucht, sondern weil ich wissen will, **warum**
Datenbanken so funktionieren, wie sie funktionieren.
Der rote Faden ist eine konkrete, ehrgeizige Frage:
> **Wie hĂ€lt man OLTP und OLAP in *einem* System gleichzeitig schnell â also HTAP â
> und wie macht SAP HANA das mit Delta und Main?**
paulDB ist die Antwort, die ich mir selbst mit Code gebe. Mein âCrafting Interpreters",
nur fĂŒr Datenbanken.
---
## Der Nordstern: HTAP
Klassische Systeme zwingen zur Wahl zwischen zwei Welten:
| Workload | Optimiert fĂŒr | Speicherform | Beispiel-Query |
|---|---|---|---|
| **OLTP** | viele kleine Schreib-/Lesezugriffe | Row-Store (Zeilen) | `INSERT âŠ` · `SELECT ⊠WHERE id = 42` |
| **OLAP** | wenige groĂe Aggregationen | Column-Store (Spalten) | `SELECT kat, SUM(wert) ⊠GROUP BY kat` |
**HTAP** (Hybrid Transactional/Analytical Processing) will *beides* in einem System.
Genau das ist der einzige MaĂstab, an dem paulDB jede Entscheidung misst: Was den
HTAP-Beweis schÀrft, kommt zuerst. Alles andere wartet.
---
## Das HANA-Vorbild: Delta & Main
SAP HANA löst HTAP elegant ĂŒber zwei Bereiche pro Tabelle:
```mermaid
flowchart LR
W[Schreibzugriffe] --> DELTA["DELTA
Row-Store · schreib-optimiert"]
R[Leseanalysen] --> MAIN["MAIN
Column-Store · lese-optimiert, komprimiert"]
DELTA -- "Delta-Merge (periodisch)" --> MAIN
```
- **Delta** â schreib-optimiert, nimmt neue Daten schnell auf (OLTP-Seite).
- **Main** â lese-optimiert, stark komprimiert, ideal fĂŒr Analytik (OLAP-Seite).
- **Delta-Merge** â schiebt periodisch Delta â Main und hĂ€lt Lesezugriffe schnell.
Genau dieses Prinzip ist das HerzstĂŒck von paulDB.
---
## Architektur (in-memory, HTAP-zentriert)
In-Memory ist hier **kein Kompromiss** â es ist authentisch: HANA ist primĂ€r in-memory,
Delta und Main leben im RAM. Persistenz auf Platte ist deshalb eine *optionale*
spÀtere Etappe, nicht das Fundament.
```mermaid
flowchart TD
SQL["SQL-Frontend
Tokenizer â AST â Planner"]
ROUTER{"Query-Router
OLTP oder OLAP?"}
DELTA["DELTA · Row-Store
(in-memory, schreib-optimiert)"]
MAIN["MAIN · Column-Store
(in-memory, komprimiert)"]
MERGE["Delta-Merge-Worker
(periodisch)"]
SQL --> ROUTER
ROUTER -->|"INSERT / Punkt-SELECT"| DELTA
ROUTER -->|"GROUP BY / Aggregation"| MAIN
DELTA -. "Lese-Queries sehen Delta âȘ Main" .-> MAIN
DELTA ==>|merge| MERGE ==> MAIN
```
---
## Kernideen im Detail
### Delta (Row) vs. Main (Column)
Eine Zeile in den **Delta**-Store zu schreiben ist billig â man hĂ€ngt sie hinten an.
Ăber eine **Spalte** im **Main**-Store zu aggregieren ist billig â alle Werte einer
Spalte liegen zusammenhÀngend und cache-freundlich im Speicher. paulDB nutzt beide
StĂ€rken und ĂŒberbrĂŒckt sie mit dem Merge.
### Kompression im Column-Store â der Deep-Dive đŹ
Hier gehen wir **so realistisch und tief wie möglich** und bauen HANAs zweistufiges
Modell nach.
**Stufe 1 â Dictionary-Encoding (immer):**
Jede Spalte bekommt ein sortiertes Wörterbuch ihrer distinct-Werte. Die eigentliche
Spalte wird zu einem Vektor aus **Integer-Value-IDs** (Index ins Wörterbuch). Das
allein macht die Spalte klein *und* macht Scans/Aggregationen schnell, weil man ĂŒber
kompakte Integer statt ĂŒber Strings lĂ€uft.
**Stufe 2 â Advanced Compression** auf den Value-ID-Vektor. Pro Spalte wird das
gĂŒnstigste Verfahren gewĂ€hlt:
| Verfahren | Idee | Stark bei |
|---|---|---|
| **Prefix** | hÀufigen Anfangswert einmal speichern | Spalten mit dominantem Startwert |
| **Run-Length (RLE)** | âWert Ă Anzahl" statt Wiederholungen | langen WiederholungslĂ€ufen |
| **Cluster** | Blöcke aus wiederkehrenden Mustern | lokal geclusterten Werten |
| **Sparse** | hĂ€ufigsten Wert weglassen, nur Ausnahmen speichern | dĂŒnn besetzten Spalten |
| **Indirect** | gemeinsame Werte ĂŒber Blöcke indirekt referenzieren | mittlerer KardinalitĂ€t |
Das ist exakt die Familie, die HANA auf seinen Column-Store legt â und genau das
Rabbit-Hole, in dem das âWarum" wohnt.
### Query-Router = der HTAP-Beweis
Der Router ist der Moment, in dem paulDB sichtbar HTAP wird: dieselbe Engine bedient
ein `SELECT ⊠WHERE id = âŠ` ĂŒber den Row-Pfad (Delta + Main) und ein
`⊠GROUP BY âŠ` ĂŒber den Column-Pfad (Main). Ein Lese-Query sieht dabei immer
**Delta âȘ Main**, damit frisch geschriebene Daten sofort in der Analytik auftauchen.
---
## Roadmap
Etappenweise â jede Stufe ist fĂŒr sich ein vollstĂ€ndiges Lernziel.
*(Reihenfolge ist Plan, kein Versprechen an einen Zeitpunkt. Erst wenn das
SAP-Fundament steht.)*
- [ ] **E0 â Rust-Fundament + Repo-Setup** · `cargo`, Projektstruktur, Tests, CI
- [ ] **E1 â In-Memory Row-Store (Delta)** · Tabellen, Schema, `INSERT`, Full-Scan
- [ ] **E2 â Mini-SQL-Parser** · Tokenizer â AST â Executor: `INSERT` + `SELECT ⊠WHERE`
- [ ] **E3 â In-Memory Column-Store (Main)** · spaltige Daten + tiefe Kompression (Dictionary â Prefix/RLE/Cluster/Sparse/Indirect)
- [ ] **E4 â Delta-Merge** â€ïž · periodischer Merge Delta(row) â Main(column) â *der Nordstern*
- [ ] **E5 â Query-Router** · Punktabfrage â Row-Pfad, Aggregation â Column-Pfad â *der HTAP-Beweis*
- [ ] **E6 â SQL-Ausbau** · `GROUP BY`, `SUM/COUNT/AVG`, dann `JOIN`
- [ ] **E7 â MVCC / Transaktionen (leicht)** · konsistente Lesersicht wĂ€hrend des Merge
- [ ] **E8 â *(optional)* Persistenz** · WAL + Snapshot: aus âBeweis" wird âechte DB"
---
## Design-Entscheidungen (Mini-ADR)
Drei bewusste Weichen, an denen sich alles ausrichtet:
1. **Nordstern = HTAP-Beweis.** Jede Etappe dient dem Ziel, Delta-Merge + Row/Column
in einer Engine zu zeigen. Deshalb steht Delta-Merge bei **E4**, nicht am Ende.
2. **In-Memory zuerst.** Authentisch zu HANA, schneller Erfolg. Platte ist optional (E8).
3. **Volles SQL als Fernziel.** Start mit Mini-SQL (E2), bewusst auf `GROUP BY`/`JOIN`
hingebaut (E6) â denn ohne Aggregationen kann man die OLAP-Seite nicht vorfĂŒhren.
KomplexitĂ€ts-Notiz fĂŒrs GefĂŒhl: ein Full-Scan ist $O(n)$, ein spĂ€terer Index-Lookup
ĂŒber einen B-Tree wĂ€re $O(\log n)$ â der Unterschied, der OLTP erst schnell macht.
---
## Repo-Features, die paulDB nutzt
Mein Gitea ist ĂŒberraschend mĂ€chtig fĂŒr dieses Projekt:
- **Projects (Kanban-Board)** â die Roadmap-Etappen als sichtbare Karten (To Do / In Progress / Done).
- **Milestones** â E0âE8 als Meilensteine, gefĂŒllt mit Issues.
- **Packages â Cargo-Registry** đŠ â paulDB-Crates landen in *meiner eigenen* Rust-Registry statt auf crates.io.
- **Actions (CI/CD)** â bei jedem Push automatisch `cargo build` + `cargo test`.
- **Wiki** â Platz fĂŒr tiefe Design-Docs jenseits dieses README.
---
## Lernressourcen
Die Schultern, auf denen paulDB steht:
- đ **Database Internals** â Alex Petrov *(Storage Engines, B-Trees, MVCC, WAL)*
- đ **Crafting Interpreters** â Robert Nystrom *(Tokenizer, AST â fĂŒrs SQL-Frontend)*
- đ» **[cstack/db_tutorial](https://cstack.github.io/db_tutorial/)** *(eine DB Schritt fĂŒr Schritt)*
- đïž **SQLite Source Code** *(das Vorbild fĂŒr âklein, robust, vollstĂ€ndig")*
- đŠ **The Rust Programming Language** (âthe Book") + **Rust by Example**
- đ§ **SAP HANA Administration Guide** *(Delta-Merge & Column-Store-Kompression im Original)*
---
## Status
đ± **Vision-Phase.** paulDB ist aktuell ein Zuhause fĂŒr einen Traum, der bewusst wartet,
bis mein SAP-Fundament steht. Das ist kein RĂŒckstand â das ist Reihenfolge.
Ein leeres Repo mit klarem Plan ist kein Hochstapeln. Es ist ein Versprechen an mich selbst.
---
von Paul Horn · gebaut, um zu verstehen · auf dem Weg nach BC đïž