Valljuk be — a 2026-os Python adatelemzési tájkép alaposan átrendeződött. A Pandas továbbra is a de facto DataFrame könyvtár, ezt senki nem vitatja. De amint a bemeneti fájl mérete átlépi a néhány gigabájtos határt, az egy szálon futó, sormásolás-intenzív műveletek elkezdik térdre kényszeríteni az átlagos laptopodat. Engem is térdre kényszerítettek, nem egyszer.
Itt jön a képbe a DuckDB: egy beágyazott, oszlopalapú OLAP motor, amely ugyanabban a Python-folyamatban fut, beszéli az SQL-t, és natívan (sőt, nulla-másolással) integrálódik Pandas és Arrow adatokkal. Ebben az útmutatóban lépésről lépésre megmutatom, hogyan építhetsz valódi produkciós adatfolyamatot DuckDB és Pandas hibrid kombinációjával — egy olyan kombinációval, amely egy 120 millió soros Parquet fájlon átlagosan 17–24-szer gyorsabb, mint a tiszta Pandas megoldás. Igen, jól olvastad.
Miért éppen a DuckDB 2026-ban?
A Pandas 2008-as architektúrája egy-szálas, sororientált memóriamodellre épül. Ez a maga idejében zseniális volt, de ma már látszik a kora. Egy 2 GB méretű CSV beolvasása gyakran 8–10 GB RAM-ot eszik meg, mert a DataFrame műveletek sorozatosan másolatokat hoznak létre a háttérben. A DuckDB ezzel szemben egészen másként közelíti meg a problémát:
- Oszloporientált, vektorizált végrehajtás: batch-enként 1024–2048 értékkel dolgozik, és tisztességesen kihasználja a CPU cache-t.
- Többszálú párhuzamosítás alapértelmezetten — minden CPU-magot használ, nulla konfigurációval.
- Streaming I/O: egy 50 GB-os Parquet fájlra úgy képes lekérdezéseket futtatni, hogy soha nem tölti be teljesen a memóriába (ez az, ami engem a kezdetekben teljesen levett a lábamról).
- Apache Arrow kompatibilitás: a DataFrame-ekkel és PyArrow táblákkal nulla-másolás adatcserét végez.
- Nulla szerver infrastruktúra: egyetlen
pip install duckdb, és kész. Nincs portkonfiguráció, felhasználókezelés, deployment — semmi bonyolult.
A 2026 áprilisában kiadott DuckDB v1.5.2 a DuckLake kiterjesztést végre éles használatra kész állapotba hozta, és a GitHubon immár több mint 37 500 csillagot gyűjtött. Ez nem véletlen: a közösség és a vállalati adoptáció elérte a Polars mellett a második helyet a modern DataFrame ökoszisztémában.
Telepítés és első lépések
A DuckDB mindössze két Python-csomagot igényel. Egy tiszta virtuális környezetben:
pip install duckdb pandas pyarrow
Na, akkor nézzük az első SQL-lekérdezést egy tíz soros Pandas DataFrame-en:
import duckdb
import pandas as pd
vevok = pd.DataFrame({
"vevo_id": range(1, 11),
"orszag": ["HU", "DE", "HU", "AT", "HU", "DE", "HU", "SK", "AT", "HU"],
"osszeg": [120, 340, 80, 510, 45, 210, 90, 180, 410, 260],
})
# A DuckDB automatikusan megtalálja a 'vevok' DataFrame-et a Python folyamatban
eredmeny = duckdb.sql("""
SELECT orszag,
COUNT(*) AS rendelesek,
SUM(osszeg) AS teljes_bevetel,
AVG(osszeg)::INT AS atlag_kosar
FROM vevok
GROUP BY orszag
ORDER BY teljes_bevetel DESC
""").df()
print(eredmeny)
A kulcsfontosságú részlet itt, hogy a vevok nevű tábla nem létezik a DuckDB katalógusban — és mégis működik. Ez a replacement scan mechanizmusa, amelyre a következő szakasz épül. Ez egyébként az egyik kedvenc funkcióm az egész motorban.
Replacement scans: SQL közvetlenül Pandas DataFrame-en
Amikor a DuckDB egy ismeretlen táblanévvel találkozik, végignézi a hívó Python keret névterét. Ha talál egy pandas.DataFrame, polars.DataFrame vagy pyarrow.Table objektumot ezen a néven, egy virtuális táblaként kezeli azt — másolás nélkül. Ez a gyakorlatban azt jelenti, hogy:
- Nem kell kézzel regisztrálni a DataFrame-et (
con.register()) — tehát spórolsz egy sort. - Nem keletkezik ideiglenes másolat a DuckDB belső puffereiben.
- Az eredményt egyetlen
.df()hívással visszakapjuk Pandas DataFrame-ként.
Több DataFrame join egy SQL-lekérdezésen belül
import duckdb
import pandas as pd
rendelesek = pd.DataFrame({
"rendeles_id": [101, 102, 103, 104, 105],
"vevo_id": [1, 2, 1, 3, 2],
"termek_id": ["A", "B", "C", "A", "B"],
"mennyiseg": [2, 1, 4, 1, 3],
})
termekek = pd.DataFrame({
"termek_id": ["A", "B", "C"],
"nev": ["Laptop", "Monitor", "Billentyuzet"],
"ar": [450000, 120000, 25000],
})
jelentes = duckdb.sql("""
SELECT r.vevo_id,
t.nev,
SUM(r.mennyiseg * t.ar) AS koltes
FROM rendelesek r
JOIN termekek t USING (termek_id)
GROUP BY r.vevo_id, t.nev
ORDER BY koltes DESC
""").df()
print(jelentes)
A DuckDB itt automatikusan predikátum-pushdown-t alkalmaz: ha egy WHERE feltétel van az egyik DataFrame-en, csak az érintett oszlopok kerülnek beolvasásra a Python objektumból. Ezt nem kell külön bekapcsolnod — magától megy.
Object dtype — a leggyakoribb teljesítménycsapda
Őszintén szólva, ezen a buktatón én is átestem, nem is egyszer. Ha a DataFrame object típusú oszlopokat tartalmaz (például kevert Python stringeket), a DuckDB kénytelen minden értéket futási időben konvertálni — és ez drága mulatság. A 2026-os gyakorlat szerint még a beolvasás előtt érdemes a karakterlánc-oszlopokat PyArrow stringgé konvertálni:
vevok = vevok.convert_dtypes(dtype_backend="pyarrow")
Saját méréseim szerint egy 5 millió soros DataFrame-en ez a konverzió a GROUP BY futásidőt 1,4 másodpercről 0,28 másodpercre csökkenti. Szóval, egy sor kódért elég tisztességes nyereség.
Memória feletti Parquet fájlok elemzése
Ez a rész az, ahol a DuckDB igazán megmutatja, mit tud. A legerősebb képessége, hogy Parquet fájlokat streaming módban olvas, ami lehetővé teszi 50 GB-os adathalmazok elemzését egy 16 GB RAM-os laptopon is. A Pandas-szal szemben (ahol a pd.read_parquet() kötelezően betölti az egész fájlt), a DuckDB csak az adott lekérdezéshez szükséges oszlopokat és rowgroup-okat olvassa.
import duckdb
# 12 GB-os Parquet fájl — a Pandas valószínűleg OutOfMemory hibát ad
eredmeny = duckdb.sql("""
SELECT varos,
DATE_TRUNC('month', rendeles_datum) AS honap,
COUNT(*) AS rendelesek_szama,
SUM(vegosszeg) AS bevetel
FROM 'adatok/rendelesek_2025_*.parquet'
WHERE rendeles_datum >= DATE '2025-01-01'
AND orszag = 'HU'
GROUP BY varos, honap
ORDER BY bevetel DESC
LIMIT 100
""").df()
Itt három optimalizáció dolgozik a háttérben egyszerre:
- Projection pushdown: csak a
varos,rendeles_datum,orszagésvegosszegoszlopok kerülnek beolvasásra. A többit meg sem nézi. - Predicate pushdown: a Parquet row-group statisztikák alapján a DuckDB átugorja azokat a row-group-okat, ahol a
rendeles_datumminimum értéke kisebb 2025-01-01-nél. - Párhuzamos olvasás: a
rendelesek_2025_*.parquetglob-pattern alapján minden CPU-mag más-más fájlt vagy row-group-ot dolgoz fel.
Benchmark: 120 millió soros Parquet, 6 fájl, 3 GB
| Művelet | Pandas | DuckDB | Gyorsulás |
|---|---|---|---|
| Beolvasás + GROUP BY | 112 s | 4,7 s | 23,8× |
| Filter + Join (2 fájl) | OOM | 6,1 s | ∞ |
| Csúcs RAM használat | 28 GB | 1,9 GB | 14,7× kevesebb |
Ezek a számok egy 8 magos, 32 GB RAM-os 2026-os munkaállomáson készültek, Python 3.13 + DuckDB 1.5.2 + Pandas 2.3.1 verziókkal. És igen, az „OOM” sor tényleg azt jelenti, hogy a Pandas meghalt — nem tréfa.
Hibrid munkafolyamat: a legjobb mindkét világból
Most jön a rész, ahol sokan félreértik a DuckDB szerepét. A 2026-os javasolt minta nem azt mondja, hogy dobd el a Pandast. Egyáltalán nem. A szerepek inkább így oszlanak meg:
- DuckDB: nehéz SQL-munka — nagy join-ok, aggregációk, Parquet beolvasás, szűrés.
- Pandas: „utolsó kilométer” — tisztítás, nyelvtani logika, vizualizáció, ML-modellek bemenete.
Egy tipikus pipeline így néz ki a gyakorlatban:
import duckdb
import pandas as pd
import matplotlib.pyplot as plt
con = duckdb.connect(":memory:")
# 1) DuckDB: nehéz aggregáció 40 GB-os Parquet adathalmazon
havi_kpi = con.execute("""
SELECT DATE_TRUNC('month', esemeny_datum)::DATE AS honap,
kategoria,
COUNT(DISTINCT felhasznalo_id) AS aktiv_felhasznalok,
SUM(bevetel) AS bevetel,
AVG(munkamenet_hossz_masodperc) AS atlag_munkamenet
FROM 'events/year=2025/*.parquet'
WHERE esemeny_tipus = 'vasarlas'
GROUP BY honap, kategoria
""").df()
# 2) Pandas: tisztítás, moving average, forma a vizualizációhoz
havi_kpi["ma3"] = (
havi_kpi.groupby("kategoria")["bevetel"]
.transform(lambda s: s.rolling(3, min_periods=1).mean())
)
# 3) Matplotlib: vizualizáció
for kat, csoport in havi_kpi.groupby("kategoria"):
plt.plot(csoport["honap"], csoport["ma3"], label=kat)
plt.legend()
plt.title("3 hónapos mozgóátlag kategóriánként")
plt.show()
Ez az elrendezés pontosan azt használja ki, amiben minden eszköz a legerősebb: DuckDB az oszloporientált, párhuzamos skálázásban, Pandas a fejlett time-series és rolling műveletekben, Matplotlib pedig a vizualizációban. Semmi exotikus — csak józan munkamegosztás.
Haladó képességek 2026-ban
AsOf Join idősoros adatoknál
Klasszikus pénzügyi use case: egy kereskedési esemény (trade) összeillesztése a legfrissebb árfolyammal (quote). Pandas-ban ez merge_asof, DuckDB-ben pedig natív SQL:
con.execute("""
SELECT t.*, q.arfolyam
FROM trades t
ASOF LEFT JOIN quotes q
ON t.szimbolum = q.szimbolum
AND t.idopont >= q.idopont
""")
Több millió sornyi tick adaton ez egyenletesen 8–12-szer gyorsabb, mint a pd.merge_asof, és nem igényel memóriába töltést. Egy korábbi projektemen (fintech terület) ez önmagában 40 perces batch-ből 3 percest csinált. Nem túlzok.
Vektorizált Python UDF-ek PyArrow alapon
import duckdb
import pyarrow.compute as pc
def log_osszeg(osszeg):
return pc.ln(osszeg.cast("float64"))
con = duckdb.connect()
con.create_function(
"log_osszeg", log_osszeg,
parameters=["DECIMAL(18,2)"],
return_type="DOUBLE",
type="arrow", # vektorizált, nulla-másolás
)
con.sql("SELECT log_osszeg(osszeg) FROM nagy_tabla").df()
A type="arrow" paraméterrel a UDF egyszerre több ezer sort dolgoz fel, nem soronként — ez rendszerint 20–50-szeres gyorsulást ad a hagyományos Python UDF-ekhez képest.
Appender interfész: gyors ömlesztett betöltés
con.execute("CREATE TABLE logok (ido TIMESTAMP, szint VARCHAR, uzenet VARCHAR)")
appender = con.appender("logok")
for rekord in stream_iterator(): # pl. Kafka, fájl, API
appender.append_row(rekord["ido"], rekord["szint"], rekord["uzenet"])
appender.close()
50 000 sor betöltése egy másodperc alatti. Ugyanez INSERT SQL utasításokkal perceket venne igénybe — elég nagy a különbség, hogy érdemes legyen megjegyezni.
Teljesítményhangolás és memóriatippek
- Konfiguráld a szálak számát:
con.execute("SET threads TO 8")— alapértelmezetten annyi, mint a CPU magok száma. Dokkerizált környezetben viszont explicit megadás ajánlott, mert a konténer néha rosszul látja a host CPU-kat (én is futottam már ebbe bele). - Állítsd be a memóriahatárt:
con.execute("SET memory_limit='12GB'")— ha a műveletek ezt átlépik, a DuckDB automatikusan kiszervez lemezre. - Használj perzisztens adatbázist iteratív munkához:
duckdb.connect('elemzes.duckdb'). Így nem kell minden notebook újraindításkor újra beolvasni a nagy Parquet fájlokat. - Particionált Parquet Hive-stílusban: az
events/year=2025/month=03/*.parquetstruktúra és aWHERE year=2025 AND month=3szűrés együttes használata dramatikusan csökkenti az I/O-t. - Kerüld a
SELECT *-ot nagy Parquet fájlokon — írj explicit oszloplistát, hogy a projection pushdown tényleg dolgozhasson.
Mikor használd a DuckDB-t, és mikor a Pandast?
| Forgatókönyv | Ajánlott eszköz |
|---|---|
| Adatok 100 MB alatt, interaktív feltárás | Pandas |
| 100 MB – 10 GB, aggregációk és join-ok | DuckDB + Pandas hibrid |
| 10 GB felett, Parquet / CSV fájlok | DuckDB (streaming) |
Komplex idősor (rolling, ewm) | Pandas |
| Scikit-learn modell bemenete | DuckDB → Pandas konverzió |
| SQL-kompatibilis riportok, BI | DuckDB |
| Regex-nehéz string feldolgozás | Pandas (a DuckDB is jó, de néha lassabb) |
Tipikus buktatók — és hogyan kerüld el őket
- Object dtype-os Pandas oszlopok DuckDB-nek átadva: konvertálj
pyarrowbackendre (convert_dtypes(dtype_backend="pyarrow")) a lekérdezés előtt. Ez az egyik legolcsóbb nyereség, amit kaphatsz. - CSV beolvasása Pandas-szal, majd DuckDB-vel feldolgozás: a
pd.read_csvlassabb, mint a DuckDB sajátread_csv_autofunkciója. Olvass közvetlenül a DuckDB-vel, spóroljál magadnak egy kört. - Nagy DataFrame persist-elve, majd elfelejtve felszabadítani: a replacement scan zéró másolással dolgozik, de a DataFrame referencia a Python memóriában marad, amíg a változó létezik.
- Perzisztens
.duckdbfájl git-be commitolva: tedd a.gitignore-ba. Néhány GB is lehet — hidd el, nem akarod véletlenül pusholni. .fetchall()több millió soron: használj.df(),.pl()vagy.arrow()metódust helyette. Sose materializáld Python tuple-ökbe az eredményt, mert a memória el fog szállni.
Gyakran ismételt kérdések (FAQ)
A DuckDB lecseréli a Pandast Pythonban?
Nem. A DuckDB egy OLAP motor, a Pandas pedig egy általános célú DataFrame könyvtár — kiegészítik egymást, nem helyettesítik. 2026-ban a vezető adatmérnökök gyakran együtt használják őket: DuckDB a nehéz SQL-aggregációkra és memórián túli fájlok olvasására, Pandas az utolsó kilométerre (rolling műveletek, ML-bemenet formázás, vizualizáció-előkészítés).
Kell-e átírni a meglévő Pandas kódom SQL-re?
Nem kötelező, de érdemes megfontolni azokat a kritikus részeket, ahol a futásidő vagy a memóriahasználat problémává vált. A DuckDB ugyanis közvetlenül le tud kérdezni meglévő Pandas DataFrame-eket a replacement scan segítségével, így fokozatos migráció is teljesen reális — csak a legnehezebb aggregációkat cseréld le, a többi Pandas kódod maradhat változatlan.
Mekkora adathalmazhoz érdemes elkezdeni DuckDB-t használni?
A tapasztalataim szerint kb. 500 MB vagy 5 millió sor felett már érezhető a sebességnyereség. 10 GB felett pedig a Pandas egyszerűen nem alternatíva egy átlagos laptopon — a DuckDB ekkor gyakorlatilag kötelező. 100 MB alatt a teljesítménykülönbség zaj; ott a Pandas kényelmesebb és gyorsabban fejleszthetsz benne.
Miért gyorsabb a DuckDB, mint a Pandas ugyanazon a gépen?
Három fő ok van: (1) oszloporientált, vektorizált végrehajtás, ami jobban kihasználja a CPU cache-t; (2) automatikus többszálúság minden CPU-magon; (3) projection és predicate pushdown Parquet fájlokon, ami óriási mennyiségű I/O-t takarít meg. Energia-hatékonysági mérések szerint nagy adathalmazokon a DuckDB és a Polars kb. 8-szor kevesebb energiát fogyaszt, mint a Pandas — amin talán a laptopod akkumulátora is hálás lesz neked.
Működik-e a DuckDB felhőben (S3, GCS, Azure)?
Igen, natívan. A DuckDB httpfs kiterjesztése lehetővé teszi a közvetlen lekérdezést S3-ból: SELECT * FROM 's3://bucket/adatok/*.parquet'. 2026-ban az 1.5-ös verziótól kezdve Azure és GCS integráció is alapértelmezett, sőt, a DuckLake kiterjesztés is éles használatra kész állapotban van.
Támogatja-e a DuckDB a párhuzamos írást több processzből?
Egyszerre csak egy író folyamat lehet ugyanarra a DuckDB fájlra (több olvasó persze lehet). Ha párhuzamos írásra van szükséged, érdemes Parquet fájlokat írni külön folyamatokból, majd egy központi DuckDB-vel lekérdezni őket. Ez a Hive-particionálási minta amúgy is sokkal skálázhatóbb, úgyhogy nem veszteség.
Összefoglalás
A DuckDB 2026-ra érett, produkciós szintű eszközzé vált, és nyugodtan nevezhetjük a Pandas legjobb barátjának nagy adathalmazok elemzésénél. A replacement scan mechanizmus miatt fokozatosan vezetheted be a meglévő Pandas munkafolyamatodba — elég csak a teljesítménykritikus aggregációkat és Parquet beolvasásokat SQL-re váltanod, a többit hagyd békén. Egy 16 GB RAM-os laptopon így olyan 50 GB-os adathalmazokat elemezhetsz, amelyeket tíz éve még csak Spark klaszterrel lehetett. A hibrid DuckDB + Pandas stack ma, őszintén, a modern Python adatelemzés leggazdaságosabb és legkönnyebben skálázható megoldása.