Scaling Tips
1. 📂 Consultar CSVs sin cargar el fichero en memoria¶
Pandas
df = pd.read_csv("data.csv")
DuckDB
import duckdb
duckdb.query("SELECT * FROM 'data.csv'").df()
Sin read_csv() ni DataFrame. DuckDB consulta directamente al disco evitando la carga en memoria del fichero completo
2. 🔗 Join CSVs como en una base de datos (SQL)¶
SELECT a.*, b.info
FROM 'users.csv' a
JOIN 'purchases.csv' b
ON a.user_id = b.user_id
DuckDB ejecuta SQL joins contra los datos. Sin preprocesado ni ficheros temporales. No necesito 💲10GB RAM💲 😎😎
3. Si hay que usar Pandas 😢... Al menos que sea rápido 🚀¶
import pandas as pd
import duckdb
df = pd.read_csv("bigfile.csv")
result = duckdb.query("SELECT COUNT(*) FROM df WHERE amount > 100").df()
DuckDB optimiza el acceso al DataFrame. Es del orden de 5 veces más rápido, a veces incluso más. Otro tanto aplica en relación con las consultas de agregados
SELECT country, year, SUM(sales)
FROM df
GROUP BY country, year
-- Infinitamente mejor que:
-- df.groupby(['country', 'year'])['sales'].sum().reset_index()
Sin carga ni conversión 💎💎
# ERROR: carga de datos en Pandas
big = pd.read_parquet("bigdata.parquet")
summary = big.groupby("category").amount.mean()
# No hay color
summary = con.execute("""
SELECT category, AVG(amount) AS avg_amount
FROM 'bigdata.parquet'
GROUP BY category
""").df()
Otra alternativa es usar Polars en vez de Pandas (ver DataFrame y lab)
import polars as pl
df_pl = pl.read_csv("data.csv")
duckdb.query("SELECT col1, COUNT(*) FROM df_pl GROUP BY col1").df()
Independientemente de que los datos estén en memoria, en disco o en alguna otra librería es muy probable que DuckDB los maneje directamente, sin requerir costosas conversiones (Zero ETL)
4. 🔁 SQL + Parquet = Vago pero robusto¶
La Evaluación Perezosa (más info en DataFrames y lab) es un concepto de programación que se usa a menudo en lenguajes funcionales, donde la evaluación de expresiones se retrasa hasta que sus resultados sean realmente necesarios. Este enfoque ayuda a optimizar la ejecución de los programas mediante la reducción de la carga computacional, permitiendo un procesamiento y asignación eficiente de los recursos. Funciona organizando tareas de computación en unidades más pequeñas y manejables, llamadas thunks, que solo se ejecutan cuando se requieren sus resultados. Las características clave son:
- Computación diferida: El cálculo de las expresiones se pospone hasta que los valores sean explícitamente necesarios
- Uso eficiente de los recursos: Reduce el consumo de memoria y la sobrecarga computacional al evitar cálculos innecesarios
- Ejecución de consultas optimizada: optimiza el procesamiento de consultas complejas de múltiples pasos mediante la consolidación de múltiples operaciones en un solo pase de evaluación
# pd.read_parquet() killer ⚱️
duckdb.query("SELECT * FROM 'logs_2025.parquet' WHERE status = 'error'").df()
Usando Polars como mediador¶
import polars as pl
# Lazy load a big parquet
pl_df = pl.scan_parquet("bigdata.parquet")
# Query it directly with DuckDB
result = con.execute("""
SELECT category, SUM(amount) as total_amount
FROM pl_df
GROUP BY category
""").pl()
print(result)
5. 🧹 Limpieza de los Pipelines SQL en Python¶
DuckDB facilita la legilibilidad del código de la ETL
q = """
WITH cleaned AS (
SELECT * FROM 'sales.csv'
WHERE price IS NOT NULL
),
aggregated AS (
SELECT region, AVG(price) as avg_price
FROM cleaned
GROUP BY region
)
SELECT * FROM aggregated
ORDER BY avg_price DESC
"""
df = duckdb.query(q).df()
Que pasen a escena las vistas temporales 🫵🫵
con.execute("CREATE VIEW sales AS SELECT * FROM 'sales.parquet'")
con.execute("CREATE VIEW customers AS SELECT * FROM 'customers.parquet'")
result = con.execute("""
SELECT c.region, SUM(s.amount) AS revenue
FROM sales s
JOIN customers c ON s.customer_id = c.id
GROUP BY c.region
""").df()
Legible. Mantenible. Reproducible 💲💎💲
Tabla Resumen¶
| Comparativa | Bad Pandas |
|---|---|
![]() | ![]() |

