DuckDB

Datenbanken
SQL
R
Python
SQL für analytische Auswertungen im eigenen Prozess, direkt auf Dateien.

Kernideen

  • Wie SQLite ohne Server, aber für Auswertungen statt für Einzelzugriffe gebaut
  • Fragt CSV- und Parquet-Dateien direkt ab, ohne sie vorher zu importieren
  • Spaltenweise Speicherung: Aggregationen über viele Zeilen sind schnell
  • Arbeitet mit Data Frames aus R und Python zusammen, ohne Kopie
  • Volles analytisches SQL, inklusive Fensterfunktionen
  • Für vieles der bessere Zwischenschritt als eine Serverdatenbank

Erklärung

Vorwissen: SQL für die Abfragen. Die Einordnung gegenüber den anderen Systemen steht in der Übersicht; die Formate CSV und Parquet behandelt Datenimport und Formate.

Wofür DuckDB gebaut ist

SQLite und die Serverdatenbanken sind darauf ausgelegt, einzelne Zeilen zu lesen und zu schreiben: eine Bestellung anlegen, einen Kunden nachschlagen. DuckDB ist auf die andere Art von Frage ausgelegt, die in der Datenarbeit die übliche ist: über viele Zeilen hinweg aggregieren, gruppieren, verbinden.

Der Unterschied liegt in der Speicherung. Zeilenweise organisierte Systeme lesen ganze Datensätze; DuckDB speichert spaltenweise und liest nur die Spalten, die in der Abfrage vorkommen. Bei einer Tabelle mit fünfzig Spalten, von denen drei gebraucht werden, ist das der Unterschied zwischen Sekunden und Minuten.

Wie SQLite läuft DuckDB im eigenen Prozess: kein Server, keine Installation über den Paketmanager der Sprache hinaus, keine Rechteverwaltung.

Dateien direkt abfragen

Der praktischste Punkt im Alltag: Es braucht keinen Import. CSV- und Parquet-Dateien lassen sich unmittelbar als Tabelle ansprechen, auch mehrere auf einmal über ein Muster im Dateinamen.

SELECT standort, COUNT(*) AS n, AVG(verbrauch) AS mittel
FROM 'messungen/*.parquet'
WHERE datum >= '2026-01-01'
GROUP BY standort
ORDER BY mittel DESC;

Damit wird DuckDB zum Werkzeug für Dateien, die für den Arbeitsspeicher zu gross sind, ohne dass eine Datenbank aufgesetzt werden muss.

Zusammenspiel mit R und Python

DuckDB kann Data Frames der jeweiligen Sprache direkt als Tabelle ansprechen und Ergebnisse wieder als Data Frame zurückgeben. Damit lässt sich SQL genau dort einsetzen, wo es klarer ist als eine lange Kette von Wrangling-Schritten, ohne die Umgebung zu verlassen.

library(duckdb)
con <- dbConnect(duckdb())

duckdb_register(con, "messung", messung_df)      # Data Frame als Tabelle
ergebnis <- dbGetQuery(con, "
  SELECT standort, AVG(verbrauch) AS mittel
  FROM messung GROUP BY standort")
import duckdb

messung = pd.read_parquet("messung.parquet")

ergebnis = duckdb.sql("""
    SELECT standort, AVG(verbrauch) AS mittel
    FROM messung GROUP BY standort
""").df()

In Python wird der Data Frame messung einfach über seinen Namen angesprochen; eine Registrierung ist nicht nötig.

Wann DuckDB, wann etwas anderes

Fall Passend
Grosse Dateien auswerten, einmal oder wiederholt DuckDB
Wenige Zeilen laufend lesen und schreiben SQLite oder Serverdatenbank
Mehrere Personen greifen gleichzeitig schreibend zu PostgreSQL
Daten liegen bereits in einer Serverdatenbank Dort aggregieren, siehe PostgreSQL
Ergebnisse langfristig aufbewahren und pflegen Serverdatenbank

Typische Aufgaben

Eine Datei ansehen, ohne sie zu laden

SELECT * FROM 'daten.csv' LIMIT 10;
DESCRIBE SELECT * FROM 'daten.csv';        -- Spalten und erkannte Typen
SELECT COUNT(*) FROM 'daten.parquet';

Viele Dateien als eine Tabelle behandeln

SELECT * FROM read_parquet('messungen/*.parquet');
SELECT * FROM read_csv_auto('export_2026_*.csv', union_by_name = true);

Formate umwandeln

COPY (SELECT * FROM 'gross.csv') TO 'gross.parquet' (FORMAT parquet);

Parquet ist spaltenweise, komprimiert und typsicher; als Zwischenformat für grosse Zwischenstände ist es CSV deutlich überlegen.

Ergebnis zurück in die Sprache holen

df <- dbGetQuery(con, "SELECT * FROM 'gross.parquet' WHERE standort = 'Bern'")
df = duckdb.sql("SELECT * FROM 'gross.parquet' WHERE standort = 'Bern'").df()

Eine dauerhafte Datenbankdatei verwenden

con <- dbConnect(duckdb(), dbdir = "analyse.duckdb")
verbindung = duckdb.connect("analyse.duckdb")

Aus einer anderen Datenbank lesen

INSTALL postgres; LOAD postgres;
ATTACH 'dbname=produktion host=db.example.org' AS pg (TYPE postgres);
SELECT COUNT(*) FROM pg.public.bestellung;

So lassen sich Daten aus einer Serverdatenbank mit lokalen Dateien in einer einzigen Abfrage verbinden.

Verständnisfragen

Die Beispiele auf dieser Seite sind Listings: DuckDB ist in der Umgebung, die diese Website baut, nicht installiert, deshalb wird hier nichts gerechnet. Wo Abfragen wirklich laufen, steht es dabei, etwa unter SQL und SQLite.

Eine Parquet-Datei mit 80 Millionen Zeilen und 60 Spalten soll nach Monat aggregiert werden; drei Spalten werden gebraucht. Was ist der schnellste Weg?

Die Datei mit pandas laden und gruppieren
Der Speicher reicht dafür selten, und geladen würden alle 60 Spalten.
Die Datei direkt mit DuckDB abfragen
Richtig. Gelesen werden nur die drei benötigten Spalten und nur die benötigten Abschnitte der Datei; ein Import entfällt.
Die Datei in PostgreSQL importieren und dort aggregieren
Funktioniert, kostet aber Importzeit und Infrastruktur für eine einmalige Auswertung.

Warum ist die spaltenweise Speicherung für Auswertungen im Vorteil, für eine Bestellanwendung aber nicht?

Auswertungen lesen wenige Spalten über viele Zeilen, Anwendungen ganze Datensätze einzeln
Richtig. Spaltenweise muss für einen Mittelwert nur eine Spalte gelesen werden; für eine einzelne Bestellung müssten dagegen alle Spalten aus verschiedenen Bereichen zusammengesucht werden.
Spaltenweise Speicherung ist generell schneller
Sie ist es für Aggregate, nicht für Einzelzugriffe und laufendes Schreiben.
Der Unterschied betrifft nur die Dateigrösse
Komprimierung ist ein Nebeneffekt, der Punkt ist die gelesene Datenmenge.

Wann ist SQLite die bessere Wahl als DuckDB?

Wenn laufend einzelne Zeilen gelesen und geschrieben werden
Richtig. SQLite ist auf Einzelzugriffe ausgelegt, DuckDB auf Auswertungen über viele Zeilen. Beide laufen serverlos im eigenen Prozess.
Wenn die Datei sehr gross ist
Gerade dann spielt DuckDB seine Stärke aus.
Wenn SQL verwendet werden soll
Beide sprechen SQL.

In Python lässt sich ein pandas-DataFrame in DuckDB über seinen Namen abfragen, ohne ihn zu importieren. Was bedeutet das für den Arbeitsspeicher?

Die Daten werden nicht kopiert, DuckDB liest sie an Ort und Stelle
Richtig. Deshalb ist der Wechsel zwischen SQL und pandas billig, und man kann den Teil in SQL schreiben, der dort klarer ist.
Der DataFrame wird intern in eine Datei geschrieben
Das wäre der Weg über einen Import, und genau den spart man sich.
Der Speicherbedarf verdoppelt sich
Das wäre bei einer Kopie der Fall.

Verlinkte Ressourcen