DuckDB har snabbt etablerat sig som SQLite för analys — en inbäddad, kolumnär OLAP-databas som körs i samma process som din Python-applikation. Under 2025 och in i 2026 har den passerat tio miljoner månatliga nedladdningar, och blivit standardvalet för analytisk databehandling i Python tillsammans med Pandas och Polars. Den här guiden visar varför, och hur du själv kommer igång på några minuter.
Ärligt talat? Första gången jag testade DuckDB satt jag och väntade på att en Pandas-pipeline skulle bli klar. Den hann aldrig — DuckDB svarade på samma fråga innan jag hann hämta kaffe. Sedan dess har jag haft svårt att gå tillbaka.
Vad är DuckDB och varför just nu?
DuckDB är en in-process analytisk databas skriven i C++. Till skillnad från PostgreSQL eller MySQL kräver DuckDB ingen server — biblioteket körs direkt i din Python-process, precis som SQLite. Skillnaden är att där SQLite är optimerad för transaktioner (OLTP), är DuckDB byggd från grunden för analytiska frågor (OLAP) över stora datamängder.
Det är det här som gör DuckDB så intressant 2026: du kan köra SQL-frågor direkt mot Pandas DataFrames, Polars-frames, Apache Arrow-tabeller och Parquet-filer — utan att flytta data och utan serverinstallation. Med DuckDB 1.2 (släppt under 2025) finns dessutom multi-database attach, förbättrad full-text search och inbyggt stöd för Iceberg- och Delta Lake-tabeller. Inte illa för ett bibliotek som installeras med en enda pip-rad.
När ska du välja DuckDB?
- Datamängder från 1 GB till några TB som inte får plats i minnet med Pandas.
- SQL-tunga analyser där JOIN, GROUP BY och fönsterfunktioner är centrala.
- Parquet-filer i molnet (S3, GCS, Azure) som du vill fråga utan att ladda ner allt.
- Bärbara analyspipelines där en serverlös databas förenklar deployment.
- Notebook-driven analys där SQL helt enkelt är klarare än kedjade DataFrame-anrop.
Installation och första frågan
DuckDB installeras via pip. Den enda riktiga skillnaden mot andra databaser är att det inte finns någon server att starta — och inga konfigurationsfiler att bråka med.
pip install duckdb==1.2.* pandas pyarrow
Så, det enklaste tänkbara exemplet: importera duckdb och kör en SQL-fråga som returnerar ett DataFrame.
import duckdb
result = duckdb.sql("SELECT 'Hej DuckDB' AS message, 42 AS answer").df()
print(result)
# message answer
# 0 Hej DuckDB 42
Lägg märke till att vi aldrig öppnade en anslutning eller skapade en databasfil. DuckDB använder en in-memory-databas som standard. Vill du persistera data anger du bara en sökväg:
con = duckdb.connect("analys.duckdb")
con.execute("CREATE TABLE sales AS SELECT 'A' AS region, 100 AS amount")
con.close()
SQL direkt på Pandas och Polars DataFrames
Det här är, enligt mig, DuckDB:s mest revolutionerande funktion: du kan referera till en Python-variabel som om den vore en SQL-tabell. Inget importsteg. Inget kopierande. Det bara fungerar.
import duckdb
import pandas as pd
sales = pd.DataFrame({
"region": ["Norden", "Norden", "DACH", "DACH", "UK"],
"product": ["A", "B", "A", "B", "A"],
"revenue": [1200, 850, 2100, 950, 1700],
})
top = duckdb.sql("""
SELECT region,
SUM(revenue) AS total,
AVG(revenue) AS avg_revenue
FROM sales
GROUP BY region
ORDER BY total DESC
""").df()
print(top)
Variabeln sales finns bara i Python-minnet, men DuckDB hittar den via så kallade replacement scans — den scannar de aktiva Python-ramarna när ett okänt tabellnamn dyker upp. Samma sak fungerar för Polars:
import polars as pl
sales_pl = pl.DataFrame({
"region": ["Norden", "DACH"],
"revenue": [2050, 3050],
})
duckdb.sql("SELECT region, revenue * 1.25 AS with_vat FROM sales_pl").pl()
Anropet .pl() returnerar en Polars-frame, .df() en Pandas-frame och .arrow() en Arrow-tabell. Konverteringen är zero-copy via Arrow för Polars, så det är riktigt snabbt även för stora resultatset.
Läsa Parquet, CSV och JSON utan import
DuckDB kan läsa filer direkt i SELECT-satser. Det innebär att du kan analysera data utan att först ladda in den i en DataFrame — vilket sparar både tid och minne.
duckdb.sql("""
SELECT
date_trunc('month', order_date) AS month,
COUNT(*) AS orders,
SUM(amount) AS revenue
FROM 'data/orders/*.parquet'
WHERE order_date >= '2025-01-01'
GROUP BY 1
ORDER BY 1
""").df()
Glob-mönstret data/orders/*.parquet läser alla matchande filer och behandlar dem som en enda tabell. Prediktatnedtryckning gör att DuckDB bara läser de radgrupper i Parquet-filerna som faktiskt kan innehålla rader där order_date >= '2025-01-01'. I praktiken ofta tio gånger snabbare än att läsa allt med Pandas.
För CSV finns automatisk typdetektering — supersmidigt när du bara vill skumma en fil:
duckdb.sql("SELECT * FROM read_csv('events.csv', AUTO_DETECT=TRUE) LIMIT 10").df()
Frågor mot S3 och annan molnlagring
DuckDB 1.2 har inbyggt stöd för S3, Google Cloud Storage och Azure Blob Storage via httpfs-tillägget. För publika hinkar krävs ingen konfiguration alls:
duckdb.sql("INSTALL httpfs; LOAD httpfs;")
trips = duckdb.sql("""
SELECT passenger_count, AVG(trip_distance) AS avg_distance
FROM read_parquet('s3://datasets-public/nyc-taxi/2024/*.parquet')
GROUP BY 1
ORDER BY 1
""").df()
För privata hinkar konfigurerar du en SECRET — DuckDB:s sätt att hantera autentisering utan att hårdkoda nycklar i koden:
duckdb.sql("""
CREATE SECRET s3_secret (
TYPE S3,
KEY_ID 'AKIA...',
SECRET 'xyz...',
REGION 'eu-north-1'
)
""")
Prestanda: hur står sig DuckDB mot Pandas och Polars?
I benchmarks från ClickBench och H2O-AI:s database benchmark presterar DuckDB i samma liga som Polars, och betydligt snabbare än Pandas för grupperingar och joins på datamängder från en miljon till en miljard rader. För en typisk GROUP BY på 100 miljoner rader ser tiderna ut ungefär så här på en modern bärbar dator:
- Pandas 3.0: ~14 sekunder (ofta begränsad av minne).
- Polars 1.x: ~1,2 sekunder.
- DuckDB 1.2: ~1,1 sekunder.
När data är större än RAM vinner DuckDB ofta tack vare out-of-core-exekvering: den kan spilla mellanresultat till disk och fortsätta köra frågan, något Pandas inte klarar i grundutförande.
Tre konkreta optimeringar
- Använd Parquet, inte CSV. DuckDB läser Parquet 5–10× snabbare och kan utnyttja kolumnär projektion.
- Konfigurera trådar och minne medvetet. Kör
PRAGMA threads=8; PRAGMA memory_limit='8GB';för att matcha din maskin. - Materialisera mellansteg som temporära tabeller. För komplexa pipelines är
CREATE TEMP TABLE step1 AS ...ofta snabbare än CTE:er som återanvänds flera gånger.
Integration i en typisk pipeline
Här är en realistisk ETL-skiss som extraherar från Parquet, transformerar med SQL och skriver tillbaka som partitionerad Parquet. Inget speciellt — det är bara så det brukar se ut:
import duckdb
con = duckdb.connect()
con.execute("PRAGMA threads=8")
con.execute("""
COPY (
SELECT
customer_id,
date_trunc('day', event_time) AS day,
COUNT(*) FILTER (WHERE event_type = 'purchase') AS purchases,
SUM(amount) FILTER (WHERE event_type = 'purchase') AS revenue
FROM read_parquet('s3://lake/events/year=2026/*.parquet')
GROUP BY 1, 2
)
TO 'output/daily_kpi'
(FORMAT PARQUET, PARTITION_BY (day), OVERWRITE_OR_IGNORE)
""")
Hela pipelinen körs utan att en enda rad passerar Python — DuckDB läser, aggregerar och skriver direkt. Det är ofta tio gånger snabbare än motsvarande Pandas-skript, och utan extra minnesförbrukning.
DuckDB i Jupyter med JupySQL
I notebooks är JupySQL-magin riktigt praktisk: skriv SQL i celler och få DataFrames tillbaka utan boilerplate.
%pip install jupysql duckdb-engine
%load_ext sql
%sql duckdb:///analys.duckdb
%%sql
SELECT region, SUM(revenue) AS total
FROM 'sales.parquet'
GROUP BY region
ORDER BY total DESC
Resultatet visas som en HTML-tabell och kan automatiskt konverteras till Pandas med %config SqlMagic.autopandas = True.
Vanliga fallgropar (och hur du undviker dem)
- Glöm inte stänga anslutningar i långkörande processer. Använd
with duckdb.connect(...) as con:i skript. - Replacement scans fungerar inte i alla scope. Om en DataFrame är ett klassattribut behöver du registrera den explicit:
con.register('sales', sales_df). - Datum-strängar tolkas strikt. Använd
strptime()ellerCAST(col AS DATE)snarare än att lita på implicit konvertering. - Stora SELECT *-resultat är dyra att materialisera. Filtrera och aggregera i SQL innan du kallar
.df().
FAQ
Är DuckDB snabbare än Polars?
För rena SQL-arbetslaster är de jämförbara. I många GROUP BY- och JOIN-benchmarks ligger DuckDB något före, medan Polars vinner för kedjade transformationer i Python. Välj DuckDB om du redan tänker i SQL, och Polars om du föredrar ett DataFrame-API.
Kan DuckDB ersätta PostgreSQL?
Nej, inte för transaktionella arbetslaster. DuckDB är optimerad för analys (OLAP) — många läsningar och stora aggregeringar. För webbappar med många små skrivningar är PostgreSQL fortfarande rätt val. Tänk på DuckDB som ett komplement, inte en ersättare.
Hur hanterar DuckDB datamängder större än RAM?
DuckDB använder en pipelinad, vektoriserad exekveringsmotor som kan spilla mellanresultat till disk när minnesgränsen överskrids. Med PRAGMA memory_limit='4GB' kan du köra frågor mot hundratals GB data så länge du har disk att spilla till.
Fungerar DuckDB med Apache Arrow?
Ja, integrationen är förstklassig. DuckDB använder Arrow internt för kolumnär datarepresentation och kan konsumera och producera Arrow-tabeller utan kopiering. Det gör det till en idealisk komponent i ett Arrow-baserat ekosystem tillsammans med Polars, PyArrow och Pandas 3.0.
Kan jag använda DuckDB i produktion?
Absolut. DuckDB nådde 1.0 i juni 2024 och har sedan dess ett stabilt lagringsformat och bakåtkompatibelt API. Den används i produktion av företag som Hex, MotherDuck och Posit. För riktigt höga krav på samtidighet eller delade dataset finns molntjänsten MotherDuck, som bygger på samma motor.
Sammanfattning
DuckDB är inte längre ett experimentellt verktyg — det är 2026 års standardval när du behöver SQL-prestanda i en Python-miljö utan komplexiteten av en serverdatabas. Genom att köra SQL direkt mot Pandas, Polars, Parquet och molnlagring täcker den ett brett spektrum av användningsfall, från ad hoc-analys i Jupyter till produktionspipelines som processar terabyte data per dag. Börja med pip install duckdb och en SELECT-sats — resten lär du dig medan du arbetar.