DuckDB i Python: Komplett guide till SQL-analys på DataFrames och Parquet (2026)
En praktisk guide till DuckDB i Python: kör snabb SQL-analys direkt på Pandas, Polars och Parquet utan separat databas. Med kodexempel, prestandajämförelser och bästa praxis.
DuckDB i Python är en inbäddad analytisk SQL-motor (OLAP) som kör frågor direkt mot Pandas-, Polars- och Arrow-tabeller samt Parquet- och CSV-filer, utan separat server och utan ETL-steg. Sedan version 1.0 (juni 2024) är fillagringsformatet stabilt och bakåtkompatibelt, och under 2026 är DuckDB ett av de snabbaste sätten att köra komplex analys på data som ryms på en enda maskin. I praktiken ser jag ofta 5 till 50 gånger snabbare aggregeringar och joins jämfört med Pandas. Den här guiden visar dig hur du installerar, frågar, prestandaoptimerar och produktionssätter DuckDB i ditt Python-arbetsflöde.
DuckDB är en process-inbäddad kolumnär databas. Installera med pip install duckdb, ingen server krävs.
Den läser och skriver Pandas DataFrames, Polars DataFrames, PyArrow-tabeller, Parquet, CSV och JSON med noll-kopiering där det är möjligt.
Senaste stabila versionen 2026 är 1.4 (Andium) med förbättrad MERGE INTO, multi-databas attach och full PIVOT-syntax.
För aggregeringar och joins på 1 till 500 GB-datamängder överträffar DuckDB ofta både Pandas och SQLite med 10 till 50 gånger.
httpfs-tillägget låter dig fråga Parquet direkt på S3, GCS eller Azure utan att ladda ner filerna först.
DuckDB är en relationsdatabas som körs i samma process som din Python-tolk, precis som SQLite, men optimerad för analytiska frågor i stället för transaktionella. Den lagrar data kolumnärt, använder vektoriserad exekvering och stöder modern SQL-syntax inklusive fönsterfunktioner, CTE:er, lateral join och rekursion. Eftersom motorn lever i din Python-process finns ingen nätverksrundtur, ingen serialisering över sockets och inget separat installationssteg.
Under 2026 är DuckDB den föredragna SQL-motorn för data science-arbetsflöden där datan ryms på en enda nod (typiskt under 500 GB). Den ersätter inte Snowflake eller BigQuery för petabyte-skala, men för det överväldigande flertalet ad hoc-analyser, ETL-jobb och rapporter ger den enklare kod, lägre latens och kraftigt minskad infrastrukturkostnad. Officiella benchmarks i DuckDB:s Python-dokumentation visar konsekvent ledning över alternativa inbäddade analytikmotorer.
Användningsfall där DuckDB lyser: explorativ analys på Parquet-arkiv, ad hoc-rapporter mot data lake-filer, ETL-mellansteg i pipelines, notebook-baserad rapportering, datakvalitetskontroller, geospatial analys och vektorlikhetsökning för retrieval-augmented generation (RAG).
Installation och första frågan
Installera DuckDB i en virtuell miljö med pip. Hjuldistributioner finns för CPython 3.8 till och med 3.13 på Linux, macOS (inklusive Apple Silicon) och Windows, så installationen tar typiskt under tio sekunder.
Den enklaste vägen är genvägen duckdb.sql(), som kör en fråga mot en intern in-minnes-anslutning och returnerar en DuckDBPyRelation. Det är ett lat objekt som inte materialiserar resultatet förrän du anropar .df(), .pl() eller .arrow().
import duckdb
# En enkel, fristående fråga
result = duckdb.sql("SELECT 42 AS svar, 'DuckDB' AS motor")
print(result) # Skriver ut en formaterad tabell
df = result.df() # Konvertera till Pandas DataFrame
pl_df = result.pl() # Konvertera till Polars DataFrame
För arbete som spänner över flera frågor (det vanliga produktionsfallet), skapa en explicit anslutning. Anslutningar är trådsäkra för läsning och stöder samtidiga markörer.
con = duckdb.connect(":memory:") # eller "min_databas.duckdb"
con.execute("CREATE TABLE forsaljning AS SELECT * FROM range(1_000_000) t(id)")
con.execute("SELECT COUNT(*) FROM forsaljning").fetchone()
# (1_000_000,)
Köra SQL på Pandas och Polars DataFrames
Det är här DuckDB blir riktigt intressant. Motorn känner igen Pandas-, Polars- och PyArrow-objekt i den lokala Python-namnrymden och behandlar dem som vore de tabeller. Ingen kopiering, ingen registrering. DuckDB läser direkt från det underliggande NumPy- eller Arrow-minnet via noll-kopierings-protokoll.
import duckdb
import pandas as pd
forsaljning = pd.DataFrame({
"produkt": ["A", "B", "A", "C", "B"],
"region": ["N", "S", "N", "N", "S"],
"belopp": [120, 75, 90, 200, 60],
})
# DuckDB ser variabeln "forsaljning" direkt
totalt = duckdb.sql("""
SELECT region, SUM(belopp) AS summa
FROM forsaljning
GROUP BY region
ORDER BY summa DESC
""").df()
print(totalt)
Samma princip gäller för Polars. Om du arbetar igenom vår guide till Polars-biblioteket kan du blanda Polars och DuckDB i samma pipeline. Polars för lazy-transformeringar, DuckDB när SQL är mer läsbart (komplexa joins, fönster, pivoter):
import polars as pl
import duckdb
orders = pl.read_parquet("orders.parquet")
# DuckDB läser Polars-frame'n in-place via Arrow
analys = duckdb.sql("""
SELECT
date_trunc('month', order_date) AS manad,
SUM(amount) AS total,
COUNT(DISTINCT customer_id) AS kunder
FROM orders
WHERE status = 'completed'
GROUP BY 1
ORDER BY 1
""").pl()
Läsa och skriva Parquet, CSV och JSON
DuckDB:s I/O är en av dess starkaste sidor. Du kan fråga ett enskilt Parquet-block, ett globmönster med tusentals filer eller en hel katalog med partitionerad data i Hive-format. Allt utan att skriva en enda rad Python.
import duckdb
# En fil
duckdb.sql("SELECT COUNT(*) FROM 'data/sales.parquet'").show()
# Globmönster över många filer (lokalt eller på S3)
duckdb.sql("""
SELECT region, AVG(amount) AS snitt
FROM 'data/year=2026/month=*/sales-*.parquet'
GROUP BY region
""").show()
# CSV med automatisk typdetektion
duckdb.sql("SELECT * FROM read_csv_auto('measurements.csv', sample_size=20000)").show()
# Newline-delimited JSON
duckdb.sql("SELECT * FROM read_json_auto('events.ndjson')").show()
För att skriva tillbaka resultat används COPY eller .write_parquet() på en relation. DuckDB skriver Parquet med Snappy-komprimering som standard och stöder partitionerad skrivning via PARTITION_BY:
# Skriv ett aggregat till partitionerad Parquet
duckdb.sql("""
COPY (
SELECT * FROM read_parquet('raw/*.parquet')
WHERE amount > 0
)
TO 'clean/' (FORMAT PARQUET, PARTITION_BY (year, month), OVERWRITE_OR_IGNORE)
""")
Om du redan rensar data med Pandas eller Polars är DuckDB en utmärkt nästa station: läs in den rensade frame'n, kör SQL-aggregeringar, skriv ut till Parquet. För grunderna i datarensning, se vår guide till datarensning med Pandas 3.0.
Persistenta databaser och transaktioner
Skicka en filsökväg till duckdb.connect() för att skapa eller öppna en persistent databas. Sedan version 1.0 är fillagringsformatet stabilt: en databas skapad med 1.0 läses utan migrering av 1.4, och senare versioner kommer att förbli bakåtkompatibla. Det gör DuckDB-filer säkra för långtidsarkivering och versionskontroll via DVC eller Git LFS.
con = duckdb.connect("warehouse.duckdb")
con.execute("""
CREATE TABLE IF NOT EXISTS kunder (
id INTEGER PRIMARY KEY,
namn VARCHAR NOT NULL,
skapad TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# Explicit transaktion
con.begin()
try:
con.execute("INSERT INTO kunder (id, namn) VALUES (1, 'Alice'), (2, 'Bob')")
con.execute("UPDATE kunder SET namn = upper(namn) WHERE id = 1")
con.commit()
except Exception:
con.rollback()
raise
con.close()
DuckDB stöder ACID-transaktioner med MVCC, vilket gör det säkert att uppdatera och skriva samtidigt som du läser. För riktigt stora skrivlaster eller komplexa upserts, använd MERGE INTO-syntaxen (tillagd i 1.2 och förbättrad i 1.4):
con.execute("""
MERGE INTO kunder t
USING (SELECT * FROM 'inkrement.parquet') s
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET namn = s.namn
WHEN NOT MATCHED THEN INSERT (id, namn) VALUES (s.id, s.namn)
""")
Fråga data på S3 och molnlagring med httpfs
httpfs-tillägget gör DuckDB till en moln-medveten frågemotor. Du kan fråga Parquet-filer som lagras på Amazon S3, Google Cloud Storage, Cloudflare R2 eller Azure Blob Storage utan att först ladda ner dem. DuckDB strömmar bara de byte-intervall den behöver, tack vare Parquets kolumnära format och footer-metadata.
import duckdb
con = duckdb.connect()
con.execute("INSTALL httpfs; LOAD httpfs;")
con.execute("""
CREATE SECRET (
TYPE S3,
KEY_ID '...',
SECRET '...',
REGION 'eu-north-1'
)
""")
# Fråga direkt på S3, ingen nedladdning
df = con.execute("""
SELECT
date_trunc('day', event_time) AS dag,
COUNT(*) AS hits
FROM read_parquet('s3://min-bucket/events/year=2026/*/*.parquet')
WHERE country = 'SE'
GROUP BY 1
ORDER BY 1
""").df()
Tack vare predikatpushdown och kolumneliminering läser DuckDB ofta bara några procent av den totala objektstorleken. Det här mönstret ersätter små Athena-, BigQuery- eller Redshift Spectrum-jobb för data science-team. Du betalar bara för S3 GET-förfrågningar och utgående trafik, inget separat scan-pris.
Hur snabb är DuckDB jämfört med Pandas och Polars?
Det korta svaret: för analytiska arbetsbelastningar (GROUP BY, JOIN, fönsterfunktioner) är DuckDB konsekvent snabbare än Pandas och konkurrerar tätt med Polars. Vid TPC-H-skala SF=100 (cirka 100 GB) presterar DuckDB och Polars båda inom samma storleksordning, ofta 10 till 50 gånger snabbare än Pandas. Den verkliga skillnaden ligger inte i råhastighet utan i ergonomi. SQL är kortare för komplexa joins och pivoter, medan Polars-uttryck är klarare för transformeringspipelines.
Egenskap
DuckDB
Polars
Pandas
Exekveringsmodell
Vektoriserad, kolumnär
Vektoriserad, kolumnär
Eager, radvis (NumPy)
Primärt API
SQL
DataFrame-uttryck
DataFrame-uttryck
Maximal datastorlek
Större än RAM (spillar till disk)
Större än RAM (lazy)
RAM-bunden
Aggregering (1 GB)
Snabbast
Snabbast
5–20× långsammare
Komplexa joins
Utmärkt (SQL)
Bra
Långsam, minnesintensiv
Fönsterfunktioner
Full SQL-syntax
Stöd via expr
Begränsat
Persistent lagring
Inbyggd (.duckdb)
Nej (Parquet)
Nej (CSV/Parquet)
Inlärningskurva
SQL (välkänt)
Brant initialt
Måttlig
I praktiken är de tre verktygen komplement, inte konkurrenter. Många team använder Polars för deterministiska transformeringspipelines och DuckDB för ad hoc-SQL och rapporter, med Pandas reserverat för kompatibilitet med äldre bibliotek (scikit-learn-pipelines som ännu inte stöder Arrow-input direkt, exempelvis).
Avancerade funktioner: UDF, fönster, PIVOT och MERGE
DuckDB:s SQL-dialekt är en av de mest moderna i någon inbäddad motor. Här är fyra funktioner som är värda att lära sig.
Python-UDF:er med Arrow
Du kan registrera vanliga Python-funktioner som DuckDB-funktioner. För skalära UDF:er sker anropet en gång per rad. För vektoriserade UDF:er passerar DuckDB ett Arrow-block och din funktion arbetar på batch-nivå, vilket ofta är 100 gånger snabbare.
import duckdb
import pyarrow as pa
def square_batch(col: pa.Array) -> pa.Array:
return pa.compute.multiply(col, col)
con = duckdb.connect()
con.create_function("square", square_batch, [int], int, type="arrow")
con.sql("SELECT square(i) FROM range(10) t(i)").show()
Fönsterfunktioner
SELECT
kund_id,
order_datum,
belopp,
SUM(belopp) OVER (
PARTITION BY kund_id
ORDER BY order_datum
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS sju_dagars_summa
FROM orders;
PIVOT och UNPIVOT
PIVOT forsaljning
ON region
USING SUM(belopp)
GROUP BY produkt;
ATTACH för multi-databas
Sedan version 1.2 kan en enda DuckDB-anslutning ha flera bifogade databasfiler. Perfekt för att kombinera ett analytiskt warehouse med en operationell databas:
ATTACH 'warehouse.duckdb' AS wh;
ATTACH 'sqlite:app.db' AS app (TYPE SQLITE);
SELECT u.name, w.lifetime_value
FROM app.users u
JOIN wh.customer_value w ON u.id = w.user_id;
Ärligt talat, efter att ha kört DuckDB i produktion i ett par projekt (senast i en notebook-pipeline som svalde 80 GB Parquet per natt) finns det några återkommande mönster som sparar tid och minne. Jag fastnade själv på ett par av dem första gången.
Använd en explicit anslutning för långa sessioner. Genvägen duckdb.sql() är fin för notebooks, men den skapar en ny implicit anslutning vid behov, vilket bryter delat tillstånd som registrerade UDF:er.
Föredra Parquet framför CSV. Predikatpushdown, kolumneliminering och Snappy-komprimering gör Parquet 5 till 20 gånger snabbare att fråga.
Sätt SET memory_limit='8GB'; i serverkontext, så att DuckDB spiller till disk i stället för att OOM-krascha din process. Det här var den bugg jag stötte på allra först.
Använd EXPLAIN ANALYZE för att se faktisk frågeplan, hash-tabell-storlekar och I/O-mängd. Det är den snabbaste vägen till att hitta saknade index eller dåliga joinordningar.
Föredra read_parquet framför read_csv_auto i pipelines. Typer är garanterade och det finns inga sample_size-överraskningar.
Var medveten om trådning. Anslutningar kan delas mellan trådar för läsning, men varje sökväg bör helst ha sin egen markör via con.cursor().
Versionsfäst tillägg. När du INSTALL httpfs; hämtas senaste versionen. Fäst med INSTALL httpfs FROM core_nightly; eller bygg tilläggen i ditt Docker-lager för repeterbarhet.
DuckDB är ett av de mest produktiva tilläggen till en Python-data scientists verktygslåda 2026. Den förenklar arkitekturen rejält. I ett av mina senaste projekt ersatte vi en hel dbt + Snowflake-uppställning med ett par hundra rader DuckDB SQL för datastorlekar under 500 GB, och fick lägre latens, bättre lokal utvecklingsupplevelse och repeterbarhet i CI på köpet. Det kändes ärligt talat lite för enkelt.
Vanliga frågor
Är DuckDB snabbare än Pandas?
Ja. För analytiska arbetsbelastningar (GROUP BY, JOIN, aggregeringar) är DuckDB konsekvent 5 till 50 gånger snabbare än Pandas, tack vare vektoriserad exekvering och kolumnär lagring. För enkla radvis-transformeringar på små DataFrames är skillnaden mindre eller obetydlig.
Kan DuckDB ersätta Snowflake eller BigQuery?
För team vars data ryms på en enda nod (typiskt under 500 GB), ofta ja. DuckDB ger samma SQL-uttrycksförmåga, snabbare lokal utveckling och kraftigt lägre kostnad. För petabyte-skala eller scenarier med många samtidiga användare behövs fortfarande ett distribuerat warehouse.
Hur stora datamängder klarar DuckDB?
DuckDB hanterar datamängder större än tillgängligt RAM genom att spilla mellanresultat till disk. I praktiken kör team analyser på 100 till 500 GB Parquet-arkiv smidigt på en bärbar dator. Frågor mot multi-terabyte data lakes via httpfs fungerar också, eftersom kolumneliminering och predikatpushdown drastiskt minskar I/O.
Stödjer DuckDB samtidiga skrivningar?
DuckDB tillåter en skrivande process åt gången på en given databasfil, men inom den processen är samtidiga läsningar och transaktionella skrivningar säkra via MVCC. För webb-applikationer med många skribenter, använd en traditionell OLTP-databas. För datapipelines med en enskild producent är DuckDB utmärkt.
Vilken Python-version krävs för DuckDB?
DuckDB 1.4 stöder officiellt CPython 3.8 till och med 3.13 på Linux, macOS (inklusive Apple Silicon) och Windows. För PyPy och alternativa runtime-miljöer kan du behöva bygga från källkod. Vi rekommenderar Python 3.11 eller senare för bästa prestanda och Arrow-interop.
Komplett guide till Optuna 4.x för hyperparameteroptimering i Python: TPE-samplern, pruners, multi-objective sökning och distribuerad körning med körbara exempel för scikit-learn och XGBoost.
Lär dig bygga reproducerbara feature engineering-pipelines i Python med scikit-learn 1.8. Komplett guide med Pipeline, ColumnTransformer, TargetEncoder och kodexempel du kan använda direkt.
Lär dig rensa data med Pandas 3.0 — hantera saknade värden, dubbletter, datatyper och outliers. Komplett guide med kodexempel och återanvändbara .pipe()-pipelines.