Published

¿Puede nuestro stack servir como ClickHouse? — investigación

Connect any source, model it as an ontology, transform it, and operationalize it, analytics, automation and machine learning, under one governed, self-hostable roof. --- Most teams stitch the...

¿Puede nuestro stack servir como ClickHouse? — investigación

Pregunta del owner: «¿y si mejoramos la estructura de DuckDB para que sea un
equivalente en nuestro stack? Identifica nuestras debilidades y los puntos fuertes
importables de los ecosistemas maduros.»

Respuesta corta: en su mayor parte sí, y no por el motor — por el LAYOUT. Casi toda
la ventaja de ClickHouse tiene equivalente en Iceberg, y hoy no estamos usando
ninguno
. Hay dos huecos que no se cierran con layout, y conviene saber cuáles son
antes de gastar una semana.


1 · Lo medido en nuestras tablas (2026-08-04)

Sobre 12 tablas del warehouse de producción, leídas por la cara REST:

con propiedades  :  2/12      ← el layout declarado sólo aterriza en 1 de cada 6
particionadas    :  0/12
con sort order   :  2/12
ficheros/tabla   :  1,1,1,1,1,1,1,1,1,1,1,1

Tres lecturas, y la tercera es la que no esperaba:

① Le damos al motor un montón de filas sin forma. Sin partición, sin orden y con un solo fichero, no hay nada que podar: el pruning es una operación por fichero y por row-group. Da igual el motor que pongas encima.

② El escritor SÍ declara un layoutwrite.target-file-size-bytes, write.parquet.row-group-size-bytes, retención de snapshots — en TABLE_WRITE_PROPERTIES (writer.py:311). Pero sólo lo aplica una de las rutas de nacimiento.

③ ⭐ Y aquí está el hallazgo: la falta de puerta de escritura (D9) no es sólo un problema de gobernanza — es un problema de RENDIMIENTO. Hay 14 nacimientos de dataset y sólo uno pasa por el chokepoint; los otros crean tablas sin propiedades, sin layout y sin política. 2/12 es exactamente esa cifra vista desde el otro lado. Cerrar la puerta de escritura no es una tarea de higiene: es la que hace que las consultas sean rápidas.

Y un cuarto dato, del código: el SortOrder se retiró del escritor porque cerraba INSERT y UPDATE (writer.py:280, D-4). O sea que el mecanismo más valioso de ClickHouse está bloqueado por la librería con la que escribimos, no por Iceberg.


2 · Mecanismo por mecanismo: qué de ClickHouse es importable

#Lo que hace ClickHouseEquivalente en Iceberg + DuckDBNuestro estado
1Columnar + vectorizado (bloques ~65 k, SIMD)✅ DuckDB es del mismo diseño, y buenoya lo tenemos
2Datos ORDENADOS + índice disperso por gránulo🟡 sort-order + partition-spec + stats por fichero y row-group0/12 · y el sort está bloqueado en el escritor
3Compresión por códec según el tipo✅ Parquet (zstd, delta, dictionary)por defecto, sin declarar
4Índices de salto (minmax, bloom)🟡 stats de manifiesto + page index de Parquetsin medir
5Vistas materializadas que agregan al INSERTARno existe en Icebergel hueco real
6Caché de resultados❌ no tenemos ningunafácil, y barato
7Disco local rápido❌ contenedores sin estado leyendo R2 por redel suelo físico

Conclusión de la tabla: de siete mecanismos, cuatro son layout que no estamos haciendo, uno ya lo tenemos, y dos son huecos de verdad.


3 · Los dos huecos que el layout NO cierra

⭐ 3.1 · Agregados incrementales (el mecanismo 5)

Es lo que hace que un count sobre mil millones sea instantáneo: no escanea mil millones, lee un estado que se mantuvo al entrar los datos. Iceberg no tiene eso.

Y aquí es donde nuestro producto tiene una ventaja que ClickHouse no tiene: el Pod. Un agregado precomputado no tiene por qué ser una vista materializada del motor — puede ser una tabla Iceberg derivada, gobernada, con su procedencia y su tier, refrescada por un scheduler. Es exactamente la forma de un Pod: un objeto de negocio consumible.

Lo que ClickHouse resuelve con una feature del motor, nosotros lo resolvemos con una primitiva de producto — más lenta de refrescar, pero auditable, versionada y legible por cualquier motor. Un agente que pregunta cuarenta veces lo mismo lee la derivada, no la tabla base.

3.2 · El suelo físico: la red hasta R2 (mecanismo 7)

Un contenedor sin estado leyendo objetos por red no va a igualar a un nodo con NVMe local, y no hay layout que lo arregle. Lo que sí se puede:

  • caché de fichero en disco local del duck-server (los Parquet calientes);
  • caché de resultados por huella de consulta — y la huella ya existe: fingerprintQuery en access-event.ts, que hoy sólo se usa para auditar.

Eso no da paridad; da que la segunda pregunta igual salga gratis. Para un producto agéntico —donde se repite mucho la misma pregunta— es donde más se nota.


4 · Las palancas, por valor y por coste

L1 · Layout en el nacimiento, por la puerta de escritura. Partición y propiedades declaradas para todas las tablas, no para 2 de cada 12. Es la palanca con mejor relación valor/coste y la que ya estaba en el plan por otra razón (D9 / I·2). Que resuelva dos problemas a la vez es la señal de que es la correcta.

L2 · Compactación y sort como trabajo de mantenimiento. Si el escritor no puede ordenar al insertar, que ordene un job después — es lo que hace todo el mundo (OPTIMIZE/rewrite_data_files). Y aquí sí hay un argumento para Trino o DuckDB en la escritura: saben escribir con orden y distribución, y pyiceberg no. Ése es un motivo mucho mejor para traer otro motor que «las consultas grandes».

L3 · Derivadas precomputadas como Pods. El sustituto de las vistas materializadas, y además encaja con el norte del producto.

L4 · Caché de resultados por huella. La huella ya está escrita.

L5 · Caché de fichero en disco en duck-server. La primera pieza con estado; medir antes si hace falta.


5 · Lo que hay que MEDIR antes de decidir nada

¿Poda DuckDB de verdad? Las fuentes públicas se contradicen: en febrero de 2026 se documenta que «hace full scan sin partition pruning», en mayo que «aprovecha el pruning de Iceberg automáticamente». No lo sabemos, y con nuestras tablas de un fichero no se puede saber — no hay nada que podar.

El experimento que lo contesta, y es de una tarde: crear una tabla con partición, orden y muchos ficheros, y comparar el escaneo con y sin filtro por la clave. Si poda, L1+L2 dan casi todo lo que se busca. Si no poda, la conversación cambia y entonces sí hay un argumento medido para un motor distinto.

Y conviene decir por qué está escrito así: hoy mismo, cuatro premisas de este repo se
cayeron por deducir una capacidad de una implementación. Ésta se queda como pregunta
hasta que alguien la mida.


6 · La respuesta a la pregunta

Sí, DuckDB puede acercarse mucho — pero no mejorando DuckDB. El motor no es el cuello de botella: le estamos dando tablas sin forma. Las cuatro primeras palancas son layout, mantenimiento y caché, y ninguna exige cambiar de motor.

Lo que no vamos a igualar sin nodos con estado es la latencia de servir agregaciones enormes con mucha concurrencia. Para eso, la opción honesta es la que ya estaba sobre la mesa: ClickHouse como capa derivada y reconstruible, con Iceberg de fuente de verdad — y sólo cuando haya un número que diga que hace falta.