--- 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 đŸ”ïž