DEV Community

William Rodriguez
William Rodriguez

Posted on

Procesa 50 millones de filas sin OOM: Query Streaming por bloques.

Procesa 50 millones de filas sin OOM: Query Streaming por bloques.

Día 09 de la serie técnica WClickHouse Open Source.

No necesitas 64GB de RAM para procesar millones de registros de ClickHouse en Python. WClickHouse query_stream() mantiene tu consumo de memoria bajo 80MB.

Los Problemas Reales

  • El OOM killer matando contenedores de Python al consultar resultados grandes
  • fetchall() cargando 10GB de datos de una consulta en la RAM de golpe
  • Arranques lentos esperando que termine toda la query antes de procesar la primera fila

La Implementación

db = WClickHouse(SensorReading, db_config)

# Stream 50 million rows in 50,000-row chunks: RAM never exceeds 80MB!
for chunk in db.query_stream("SELECT * FROM sensorreading", chunk_size=50000):
    process_batch(chunk)
    print(f"Processed chunk of {len(chunk)} rows cleanly.")
Enter fullscreen mode Exit fullscreen mode

Por qué esta arquitectura gana

  • Generador Lazy: query_stream() entrega bloques (ej. 50.000 filas) bajo demanda.
  • RAM Constante: La memoria se mantiene bajo 80MB ya sean 10k o 50M de filas.
  • Inmediatez: Comienza a procesar lógica en cuanto llega el primer bloque.

Verificación y Estado

Probado y verificado contra instancias reales de ClickHouse con más de 95% de cobertura de tests. Desarrollado para Python 3.9 a 3.14 con Apache Arrow y Pydantic v2.

ClickHouse #Python #DataEngineering #OLAP #BigData #Wisrovi

Top comments (1)

Collapse
 
william_rodriguez_65a5898 profile image
William Rodriguez •

Al procesar grandes volúmenes analíticos con stream_query(), una consideración operativa clave es la interacción entre el tamaño del bloque (block_size) y el buffer de socket del cliente HTTP en ClickHouse.

En nuestras pruebas de estrés con datasets de >50M de registros, descubrimos que ajustar el bloque entre 50,000 y 100,000 tuplas maximiza la saturación de CPU y rendimiento I/O sin superar 120 MB de memoria residente (RSS). Si el bloque es menor a 5,000, el overhead de serialización de Python penaliza el throughput general.

¿Cómo dimensionan actualmente el chunk size en sus pipelines de extracción analítica frente a límites de memoria estrictos en contenedores de Kubernetes?