DuckDB în Python: Ghid Complet pentru Analiza Datelor cu SQL în 2026

DuckDB rulează SQL direct peste DataFrame-uri pandas și fișiere Parquet, fără server și fără configurare. Vezi cum îl instalezi, când să-l alegi față de pandas sau SQLite și cum să scoți performanță maximă din interogările tale analitice în 2026.

DuckDB în Python: Ghid SQL (2026)

Actualizat: 12 iunie 2026

DuckDB în Python este o bază de date analitică (OLAP) in-process care îți permite să rulezi SQL direct peste DataFrame-uri pandas, fișiere Parquet, CSV și Arrow, fără server și fără configurare. Instalezi cu pip install duckdb, importezi modulul și execuți SQL pe orice sursă tabelară din Python. În 2026, DuckDB 1.1 a devenit instrumentul meu preferat pentru analize ad-hoc pe seturi de date de la câțiva MB până la sute de GB, cu performanță de 5–50× față de pandas la agregări și join-uri.

  • DuckDB rulează SQL direct peste DataFrame-uri pandas și Polars fără a copia date, folosind zero-copy prin Apache Arrow.
  • Pentru agregări și join-uri pe seturi mari, DuckDB e de 5–50× mai rapid decât pandas, datorită motorului vectorizat și execuției paralele.
  • Citește direct fișiere Parquet, CSV, JSON și baze externe (Postgres, SQLite, MySQL) prin extensii oficiale.
  • Versiunea 1.1 (septembrie 2025) introduce sintaxa FROM-first, funcții de fereastră îmbunătățite și suport extins pentru tipuri imbricate.
  • DuckDB nu înlocuiește pandas. Le combini: încarci și cureți în pandas, apoi agreghezi în DuckDB.
  • Procesarea out-of-core permite interogări pe fișiere mai mari decât RAM-ul disponibil, fără a încărca tot în memorie.

Ce este DuckDB și de ce să-l folosești în Python

DuckDB e o bază de date relațională orientată pe coloane, optimizată pentru sarcini analitice (OLAP). E inspirată de SQLite în ceea ce privește simplitatea instalării: totul rulează in-process, fără server separat. Spre deosebire de SQLite, care e orientat pe rânduri și optimizat pentru tranzacții (OLTP), DuckDB stochează datele columnar și folosește execuție vectorizată. Asta o face ideală pentru interogări analitice care scanează multe rânduri și agregă câteva coloane.

În practică, DuckDB rezolvă o problemă frustrantă a oricărui analist Python. Pandas devine lent și consumă mult RAM pe seturi de date de peste câțiva GB. Soluțiile clasice (Dask, Spark sau o bază Postgres dedicată) presupun configurare complexă. DuckDB îți oferă aproape toată performanța unui motor analitic distribuit direct în notebook-ul tău Jupyter, cu un singur pip install.

Honest, prima dată când am trecut un pipeline de la pandas la DuckDB, un raport zilnic care dura 11 minute a coborât la 14 secunde. N-am mai atins acel cod de atunci. Echipele de date din 2026 folosesc DuckDB pentru EDA pe fișiere Parquet de zeci de GB, pentru pipeline-uri ETL locale și pentru a interoga date stocate în S3 fără să le descarce complet.

Cazurile de utilizare tipice includ: analize ad-hoc pe loguri și fișiere CSV mari, înlocuirea unor pași costisitori de groupby din pandas, transformări intermediare în pipeline-uri ML și debugging interactiv al fișierelor Parquet generate de pipeline-uri de producție. Dacă ai încercat deja Polars ca alternativă rapidă la pandas, DuckDB e complementul SQL-first: același motor de execuție vectorizat, dar cu interfață SQL în loc de API de DataFrame.

Instalare și configurare inițială

Instalarea e directă și nu necesită dependențe de sistem. Recomand Python 3.9 sau mai nou și DuckDB 1.1+:

pip install duckdb==1.1.3
pip install duckdb pandas pyarrow  # pentru integrare completă

Primul tău script poate fi atât de scurt ca:

import duckdb

# Conexiune in-memory (efemeră, pierdută la sfârșitul procesului)
con = duckdb.connect()

# Sau persistentă pe disc (.duckdb este extensia convențională)
con = duckdb.connect("analiza_vanzari.duckdb")

# Interogare simplă
rezultat = con.execute("SELECT 42 AS raspuns").fetchall()
print(rezultat)  # [(42,)]

Pentru scripturi rapide, există și un API global care nu cere un obiect de conexiune explicit. duckdb.sql("SELECT 1") returnează direct un obiect DuckDBPyRelation evaluabil leneș. Pentru aplicații lungi sau cu mai multe fire de execuție, păstrează conexiunea explicită ca să ai control mai bun asupra stării.

Cum interoghezi un DataFrame pandas cu DuckDB

Cea mai utilă caracteristică a DuckDB pentru data scientists e capacitatea de a interoga direct DataFrame-uri pandas, ca și cum ar fi tabele SQL. Fără export, fără copiere, fără to_sql. DuckDB scanează zero-copy memoria pandas prin Apache Arrow.

import duckdb
import pandas as pd

# Construim un DataFrame pandas obișnuit
vanzari = pd.DataFrame({
    "produs": ["A", "B", "A", "C", "B", "A"],
    "regiune": ["NV", "SE", "SE", "NV", "NV", "SE"],
    "cantitate": [10, 5, 7, 3, 8, 12],
    "pret": [99.0, 149.0, 99.0, 199.0, 149.0, 99.0],
})

# DuckDB găsește automat variabila 'vanzari' din scope-ul Python
rezultat = duckdb.sql("""
    SELECT regiune,
           produs,
           SUM(cantitate * pret) AS venit_total,
           AVG(pret) AS pret_mediu
    FROM vanzari
    GROUP BY regiune, produs
    ORDER BY venit_total DESC
""").df()

print(rezultat)

Metoda .df() convertește rezultatul înapoi într-un DataFrame pandas. Alternativ, .pl() îți dă un DataFrame Polars, iar .arrow() returnează o tabelă Arrow (utilă pentru pipeline-uri care continuă cu alte instrumente columnare). Pentru iterare în streaming pe rezultate mari care nu încap în RAM, folosește .fetchmany(n) în loc de .fetchall().

Detaliul important, și aici e farmecul: DuckDB nu copiază datele din pandas. Citește direct buffer-urile NumPy și Arrow subiacente. Asta înseamnă că poți rula SQL pe un DataFrame de 5 GB fără să dublezi consumul de memorie. Dacă vii dintr-un flux de lucru bazat pe curățarea datelor cu pandas, poți încărca CSV-ul cu read_csv, cureți cu pandas, apoi treci la DuckDB pentru agregările grele.

Citirea fișierelor Parquet, CSV și JSON

DuckDB poate interoga fișiere direct, fără să le încarce în prealabil într-un DataFrame. Această capabilitate out-of-core e motivul principal pentru care a devenit popular în 2026: poți analiza un Parquet de 50 GB pe un laptop cu 16 GB RAM.

# Parquet, formatul cel mai eficient
duckdb.sql("""
    SELECT cod_tara, COUNT(*) AS nr_tranzactii, SUM(suma) AS total
    FROM 'date/tranzactii_2025_*.parquet'
    WHERE data >= '2025-01-01'
    GROUP BY cod_tara
    HAVING SUM(suma) > 100000
    ORDER BY total DESC
""").df()

# CSV cu detecție automată a tipurilor
duckdb.sql("SELECT * FROM read_csv_auto('vanzari.csv') LIMIT 10").df()

# JSON nested
duckdb.sql("""
    SELECT user.id, user.email, event.timestamp
    FROM read_json_auto('evenimente.json')
    WHERE event.type = 'purchase'
""").df()

Pattern-urile glob (*.parquet, **/anul=*/luna=*/*.parquet) funcționează nativ, iar DuckDB folosește predicate pushdown și projection pushdown. Citește din Parquet doar coloanele necesare și sare peste row group-urile care nu corespund condițiilor WHERE. În practică, asta înseamnă că o interogare bine formulată poate fi de 100× mai rapidă decât pandas.read_parquet urmat de filtrare.

DuckDB vs pandas: când să folosești fiecare

Întrebarea care apare cel mai des: înlocuiește DuckDB biblioteca pandas? Răspuns scurt, nu. Sunt complementare. Pandas excelează la manipulare per-rând, indexare bogată și integrare cu ecosistemul ML (scikit-learn, statsmodels). DuckDB excelează la SQL declarativ, agregări mari, join-uri și procesare out-of-core.

AspectpandasDuckDB
Limbaj de interogareAPI Python (chaining)SQL standard ANSI
Model de execuțieEager, single-threadVectorizat, paralel
Limita de memorieTot setul trebuie să încapă în RAMOut-of-core (spill pe disc)
Performanță agregări (1 GB)Referință 1×5–20× mai rapid
Indexare per-rândExcelent (.loc, .iloc)Limitat, orientat pe coloane
Integrare MLStandard de factoNecesită conversie la pandas/numpy
Format pe discPickle, CSV, ParquetFormat propriu .duckdb plus Parquet
Curbă de învățareAPI specific biblioteciiSQL, cunoscut de mulți

Regula mea practică: folosește pandas pentru curățare și feature engineering rând-cu-rând, pentru apply cu funcții Python complexe și pentru a alimenta modele scikit-learn. Folosește DuckDB pentru orice implică GROUP BY pe sute de mii de grupuri, join-uri între tabele mari sau interogări care depășesc RAM-ul disponibil. Un pipeline tipic în 2026 încarcă date cu DuckDB, le curăță cu pandas pentru pașii idiosincretici și revine la DuckDB pentru agregarea finală.

DuckDB vs SQLite: diferențele esențiale

DuckDB e adesea descris ca „SQLite pentru analiză", iar analogia e utilă, dar trebuie înțeleasă corect. Ambele rulează in-process. Ambele se instalează fără server. Ambele citesc și scriu un singur fișier. Diferențele apar în arhitectura motorului și în profilul de încărcare pentru care sunt optimizate.

SQLite stochează rândurile contiguu pe disc (row-oriented), optimizat pentru a citi un rând întreg rapid. Perfect pentru aplicațiile mobile sau desktop care fac multe interogări mici de tipul „dă-mi rândul cu id=42". DuckDB stochează coloanele contiguu (column-oriented), optimizat pentru a citi multe valori dintr-o singură coloană. Perfect pentru „dă-mi suma vânzărilor din ultimul an". DuckDB folosește execuție vectorizată (procesează batch-uri de 2048 de valori odată), paralelizare multi-core automată și predicate pushdown agresiv pentru Parquet.

În cifre concrete: pe un set de 100 milioane de rânduri, o agregare cu SUM și GROUP BY poate dura 45 de secunde în SQLite și sub o secundă în DuckDB. Invers, o căutare după cheie primară cu WHERE id = ? e mai rapidă în SQLite. Folosește SQLite când ai aplicație tranzacțională cu multe scrieri mici. Folosește DuckDB pentru tot ce înseamnă analiză.

Funcții de fereastră, CTE și join-uri avansate

DuckDB implementează SQL-ul ANSI 2016 aproape în întregime, inclusiv funcții de fereastră, CTE recursive, QUALIFY, PIVOT/UNPIVOT nativ și sintaxa FROM-first introdusă în versiunea 1.1. Asta îți permite să scrii interogări analitice care în pandas ar cere zeci de linii de cod.

# Calculul mediei mobile pe 7 zile și a rank-ului pe regiune
duckdb.sql("""
    WITH zilnic AS (
        SELECT
            data,
            regiune,
            SUM(suma) AS vanzari
        FROM tranzactii
        GROUP BY data, regiune
    )
    SELECT
        data,
        regiune,
        vanzari,
        AVG(vanzari) OVER (
            PARTITION BY regiune
            ORDER BY data
            ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
        ) AS media_mobila_7z,
        RANK() OVER (
            PARTITION BY data ORDER BY vanzari DESC
        ) AS rank_zilnic
    FROM zilnic
    QUALIFY rank_zilnic <= 3
    ORDER BY data, rank_zilnic
""").df()

Clauza QUALIFY e o extensie pe care DuckDB a împrumutat-o din Teradata și Snowflake: filtrează după rezultatele funcțiilor de fereastră fără un CTE intermediar. PIVOT-ul nativ înlocuiește bucle complicate cu pivot_table din pandas:

duckdb.sql("""
    PIVOT tranzactii
    ON regiune
    USING SUM(suma) AS total
    GROUP BY luna
""").df()

Pentru analize pe serii temporale similare cu cele descrise în ghidul pandas pentru DatetimeIndex și resample, DuckDB oferă funcția TIME_BUCKET și operatori interval bogați care fac group-by-on-time concis.

Extensii și conectori externi

Ecosistemul de extensii DuckDB s-a maturizat substanțial în 2025–2026. Extensiile se instalează la cerere cu INSTALL ext; și se încarcă cu LOAD ext;:

  • httpfs: citire directă din S3, GCS, Azure Blob și HTTPS, cu suport pentru credențiale via CREATE SECRET.
  • postgres_scanner: interoghează tabele Postgres ca și cum ar fi locale (util pentru join între DWH și fișiere Parquet).
  • sqlite_scanner: citește și scrie baze SQLite fără export.
  • iceberg / delta: citire de tabele Apache Iceberg și Delta Lake (suport read-only stabil în 1.1).
  • spatial: funcții geospațiale GEOS, GeoParquet, GeoJSON.
  • fts: căutare full-text cu BM25.
con = duckdb.connect()
con.sql("INSTALL httpfs; LOAD httpfs;")
con.sql("""
    CREATE SECRET s3_creds (
        TYPE S3,
        KEY_ID 'AKIA...',
        SECRET 'xxx',
        REGION 'eu-central-1'
    )
""")
con.sql("""
    SELECT category, AVG(price) AS pret_mediu
    FROM read_parquet('s3://my-bucket/catalog/*.parquet')
    GROUP BY category
""").df()

Pentru detalii complete despre extensii și formate suportate, consultă documentația oficială Python DuckDB și notele de release pe GitHub pentru cele mai recente actualizări.

Optimizare și sfaturi de performanță

Chiar dacă DuckDB e rapid din cutie, există tehnici concrete care fac diferența între o interogare de 10 secunde și una de 0.5 secunde. Începe prin a măsura cu EXPLAIN ANALYZE SELECT .... Vei vedea planul de execuție și timpul petrecut în fiecare operator.

1. Folosește Parquet în locul CSV. CSV-ul cere parsing complet la fiecare interogare, în timp ce Parquet stochează tipurile și statistici per row-group care permit skip-uri rapide. Conversia se face o singură dată cu COPY.

2. Activează multi-threading-ul explicit. DuckDB detectează automat numărul de core-uri, dar îl poți regla manual:

con.execute("SET threads TO 8")
con.execute("SET memory_limit = '12GB'")  # spill pe disc peste această limită

3. Materializează rezultatele intermediare costisitoare. Dacă reutilizezi un subset filtrat, salvează-l ca tabel temporar sau view:

con.execute("CREATE TEMP TABLE filtrat AS SELECT * FROM read_parquet('mare.parquet') WHERE an = 2025")
# acum poți face zeci de agregări peste 'filtrat' fără a recăuta fișierul

4. Profilează cu EXPLAIN ANALYZE. Pentru fiecare nod din plan, DuckDB raportează timpul, numărul de rânduri procesate și estimările cardinalității. Diferențe mari între estimare și realitate semnalează nevoia de ANALYZE sau de rescrierea interogării.

5. Pentru migrarea de la pandas, evită apply cu lambda Python. Mută cât mai mult logică în SQL pur. Funcțiile scalare definite de utilizator în Python rulează prin Apache Arrow, dar sunt totuși mai lente decât echivalentele native SQL. Pentru context despre rolul Arrow în ecosistemul DataFrame modern, vezi ghidul de migrare la pandas 3.0, unde Arrow devine backend implicit.

Întrebări frecvente

La ce se folosește DuckDB?

DuckDB se folosește pentru analiză de date OLAP in-process: agregări mari, join-uri între seturi columnar și interogări SQL ad-hoc peste fișiere Parquet, CSV sau DataFrame-uri pandas. Este folosit ca alternativă rapidă la pandas pentru seturi de la 1 GB până la sute de GB și ca motor analitic local fără configurare de server.

Este DuckDB mai rapid decât pandas?

Da, pentru agregări și join-uri DuckDB e de 5–50× mai rapid decât pandas, datorită execuției vectorizate paralele și formatului columnar. Pentru manipulări per-rând și apply cu funcții Python complexe, pandas rămâne competitiv. Pentru fișiere mai mari decât RAM, DuckDB e singura opțiune practică între cele două.

Cum instalezi DuckDB în Python?

Rulează pip install duckdb în mediul tău Python 3.9+. Pentru integrare cu pandas și Arrow, instalează și pyarrow. Nu există dependențe de sistem: pachetul DuckDB include motorul C++ precompilat pentru Linux, macOS și Windows.

Poate DuckDB să citească fișiere Parquet direct?

Da, DuckDB citește Parquet nativ cu SELECT * FROM 'fisier.parquet' sau read_parquet('cale/*.parquet'). Suportă pattern-uri glob, predicate pushdown și projection pushdown, citind doar row group-urile și coloanele necesare. Combinat cu extensia httpfs, poate citi direct din S3 și GCS fără descărcare completă.

Care este diferența dintre DuckDB și SQLite?

SQLite e orientat pe rânduri (row-store) și optimizat pentru sarcini OLTP, adică multe scrieri mici și citiri per-rând. DuckDB e orientat pe coloane (column-store) și optimizat pentru OLAP, adică agregări și scanări pe coloane. Ambele rulează in-process, dar DuckDB e de 10–100× mai rapid pe interogări analitice, iar SQLite e mai potrivit pentru aplicații tranzacționale.

Pot folosi DuckDB împreună cu pandas în același script?

Da, integrarea e zero-copy: DuckDB citește direct DataFrame-uri pandas prin Apache Arrow, fără duplicare în memorie. Convertești înapoi la pandas cu .df() pe rezultatul unei interogări. Acest pattern hibrid (pandas pentru curățare, DuckDB pentru agregări) este recomandat în majoritatea fluxurilor de analiză din 2026.

Editorial Team
Despre Autor Editorial Team

Our team of expert writers and editors.