Saltar a contenido

MergeTree

Bas谩ndose en el concepto de los 谩rboles LSM, los datos de una tabla de la familia MergeTree se almacenan en fragmentos horizontales denominados parts que, posteriormente, se fusionan en segundo plano mediante un subproceso dedicado. Cada fragmento tiene normalmente su propio directorio y los datos se organizan de forma columnar ordenados seg煤n la clave primaria

ClickHouse vs Parquet

El enfoque columnar difiere del formato columnar de Parquet, DuckDB, Snowflake o BigQuery, donde los datos se particionan primero horizontalmente en subconjuntos de filas y, dentro de cada subconjunto, las columnas se almacenan muy juntas. En ClickHouse, la tabla solo se fragmenta verticalmente y cada columna se almacena por separado
En los casos en que se escriben partes peque帽as, almacenar los datos en varios archivos separados para cada columna puede afectar negativamente al rendimiento de lectura y escritura. Por lo tanto, MergeTree ofrece dos formatos para escribir columnas:

  • Amplio: Los datos se escribir谩n en archivos separados, cada uno correspondiente a una columna
  • Compacto: Con una parte peque帽a (por defecto, menor de 10 MB), las columnas se almacenan consecutivamente en un 煤nico archivo para aumentar la localidad espacial en las lecturas y escritura

Ejemplo b谩sico

El c贸digo siguiente muestra el DDL de creaci贸n de una tabla MergeTree en ClickHouse

CREATE TABLE ejMergeTree (
  id UInt16,
  created_time Date,
  comment String
) ENGINE = MergeTree()
  ORDER BY (id, created_time)
  PARTITION BY toYYYYMM(created_time)
  TTL created_time + INTERVAL 3 MONTH;

Es importante notar los siguientes aspectos principales:

  1. No hay clave primaria expl铆cita (asume las columnas en order by)
  2. Consecuentemente, las claves primarias no garantizan la unicidad. Es decir, puede haber m煤ltiples filas con id茅ntica clave primaria
  3. Todas las escrituras son secuenciales e inmediatas
  4. Almacena de manera ordenada ya que el reparticionado de los datos ocurre en diferido
  5. El valor del TTL permite establecer un tiempo de caducidad de los datos

Indexaci贸n

A diferencia de una base de datos OLTP, los registros no tienen un 铆ndice asociado a la clave primaria. En su lugar, el 铆ndice de ClickHouse apunta a un rango de datos (Sparse Index, 铆ndice disperso). De este modo, ClickHouse puede aprovechar los 铆ndices para mejorar el rendimiento de lectura. Dado que los datos est谩n ordenados, el 铆ndice disperso permite reducir el espacio de b煤squeda durante la b煤squeda binaria. Este enfoque tambi茅n evita que el proceso de indexaci贸n afecte al rendimiento de escritura pues ser铆a muy costoso si se ingirieran millones de registros mantiendo un 铆ndice para cada uno de ellos

500

La cla煤sula PARTITION BY permite agrupar los datos de las tablas de la familia de motores MergeTree en unidades l贸gicas organizadas, lo que constituye una forma de organizar los datos que resulta conceptualmente significativa y se ajusta a criterios espec铆ficos, como intervalos de tiempo, categor铆as u otros atributos clave. Estas unidades l贸gicas facilitan la gesti贸n, la consulta y la optimizaci贸n de los datos

Esquema de particionado

ClickHouse solo fusiona partes de datos dentro de una misma partici贸n pero no entre particiones. Esto significa que las partes que pertenecen a particiones diferentes nunca se fusionan. Por consiguiente, si se elige una clave de particionado con una cardinalidad elevada las partes repartidas entre miles de particiones nunca podr谩n fusionarse. En caso extremo, el tama帽o podr铆a superar los l铆mites preconfigurados y aparecer铆a el error Too many parts. Normalmente ello de nota un esquema de particionado incorrecto pero, en todo caso, la soluci贸n es muy sencilla: elige una clave de partici贸n razonable (cardinalidad entre 1000 y 10000)

Modelo de Almacenamiento

Col

Funcionamiento MergeTree

  1. Primero ordena, almacena despu茅s
  2. Las filas se almacenan en bloques (gr谩nulos/parts) inmutables
  3. Los bloques, adem谩s de los datos, contienen los metadatos de manera que no se requiere un cat谩logo de metadatos
  4. El n煤mero de filas n cada bloque es 8192. Este valor es el denominado index granularity

1000

Col

Ingesti贸n de Datos

1750

Modelo de Ejecuci贸n en Background

Para gestionar el n煤mero de parts de cada tabla ClickHouse ejecuta peri贸dicamente en segundo plano dos procesos MS y ME combinando las partes m谩s peque帽as en otras m谩s grandes hasta que alcanzan un tama帽o comprimido configurable (normalmente, unos 150 GB). Las partes fusionadas se marcan como inactivas y se eliminan tras un intervalo de tiempo configurable. Con el paso del tiempo, este proceso crea una estructura jer谩rquica de partes fusionadas que se denomina tabla MergeTree

Col

MergeSelector (MS) y MergeExecutor (ME)

  • MS revisa tablas peri贸dicamente y planifica fusiones
  • ME selecciona y ejecuta fusiones

SelectorExecutor

Col

Agregados on-the-fly

  • Agregados acumulados en memoria (tablas hash)
  • Resultado: Merge/Sort

OnTheFly

Scan/Merge

El procesamiento de los agregados se ejecuta en paralelo sobre cada part. En el ejemplo del c谩lculo del retardo medio que muestra la consulta anterior (figura a la derecha), cuatro threads leen simult谩neamente los bloques de datos y realizan una agregaci贸n inicial al vuelo, sobre la marcha
Durante la fase de escaneo se contabiliza el n煤mero de datos (denominador) y se calcula en cada trozo la suma acumulada de los retardos (numerador). Los resultados parciales se acumulan en tablas hash donde hay una clave por cada valor de GROUP BY. Una vez finalizado el escaneo, es necesario fusionar todos los agregados y ordenarlos. La imagen a continuaci贸n muestra gr谩ficamente c贸mo funciona

avgScanMerge