MergeTree y otros motores de la familia MergeTree (p. ej., ReplacingMergeTree, AggregatingMergeTree ) son los motores de tabla más utilizados y robustos de ClickHouse.
Los motores de tabla de la familia MergeTree están diseñados para altas tasas de ingesta de datos y volúmenes de datos enormes.
Las operaciones de inserción crean partes de tabla, que un proceso en segundo plano fusiona con otras partes de tabla.
Características principales de los motores de tabla de la familia MergeTree.
- La clave primaria de la tabla determina el orden de clasificación dentro de cada parte de la tabla (índice agrupado). Además, la clave primaria no hace referencia a filas individuales, sino a bloques de 8192 filas llamados gránulos. Esto permite que las claves primarias de conjuntos de datos enormes sigan siendo lo bastante pequeñas como para permanecer cargadas en la memoria principal, sin dejar de proporcionar acceso rápido a los datos en disco.
- Las tablas pueden particionarse mediante una expresión de partición arbitraria. La exclusión de particiones garantiza que se omitan de la lectura cuando la consulta lo permita.
- Los datos pueden replicarse en varios nodos del cluster para ofrecer alta disponibilidad, failover y actualizaciones sin tiempo de inactividad. Consulte Replicación de datos.
-
Los motores de tabla
MergeTreeadmiten varios tipos de estadísticas y métodos de muestreo para facilitar la optimización de consultas.
A pesar de la similitud en el nombre, el motor Merge es diferente de los motores
*MergeTree.Crear tablas
Cláusulas de la consulta
ENGINE
ENGINE — Nombre y parámetros del motor. ENGINE = MergeTree(). El motor MergeTree no tiene parámetros.
ORDER BY
ORDER BY — La clave de ordenación.
Una tupla de nombres de columnas o expresiones arbitrarias. Ejemplo: ORDER BY (CounterID + 1, EventDate).
Si no se define ninguna clave primaria (es decir, no se especifica PRIMARY KEY), ClickHouse usa la clave de ordenación como clave primaria.
Si no se requiere ordenación, puede usar la sintaxis ORDER BY tuple().
Como alternativa, si la opción create_table_empty_primary_key_by_default está habilitada, se añade implícitamente ORDER BY () a las sentencias CREATE TABLE. Consulte Selección de una clave primaria.
PARTITION BY
PARTITION BY — La clave de partición. Opcional. En la mayoría de los casos, no necesita una clave de partición y, si necesita particionar, por lo general no hace falta una clave de partición más granular que por mes. La partición no acelera las consultas (a diferencia de la expresión ORDER BY). Nunca debe usar una partición demasiado granular. No particione sus datos por identificadores o nombres de clientes (en su lugar, haga que el identificador o el nombre del cliente sea la primera columna de la expresión ORDER BY).
Para particionar por mes, use la expresión toYYYYMM(date_column), donde date_column es una columna con una fecha del tipo Date. Los nombres de las particiones aquí tienen el formato "YYYYMM".
PRIMARY KEY — La clave primaria, si difiere de la clave de ordenación. Opcional.
Especificar una clave de ordenación (mediante la cláusula ORDER BY) implica especificar también una clave primaria.
Por lo general, no es necesario especificar la clave primaria además de la clave de ordenación.
SAMPLE BY
SAMPLE BY — Una expresión de muestreo. Opcional.
Si se especifica, debe estar incluida en la clave primaria.
La expresión de muestreo debe dar como resultado un entero sin signo.
Ejemplo: SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID)).
TTL
TTL — Una lista de reglas que especifican el tiempo de almacenamiento de las filas y la lógica del movimiento automático de partes entre discos y volúmenes. Opcional.
La expresión debe dar como resultado un Date o DateTime, por ejemplo, TTL date + INTERVAL 1 DAY.
El tipo de regla DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'|GROUP BY especifica la acción que debe realizarse con la parte si se cumple la expresión (se alcanza el momento actual): eliminación de filas vencidas, movimiento de una parte (si la expresión se cumple para todas las filas de una parte) al disco especificado (TO DISK 'xxx') o al volumen (TO VOLUME 'xxx'), o agregación de valores en las filas vencidas. El tipo predeterminado de la regla es la eliminación (DELETE). Se puede especificar una lista con varias reglas, pero no debe haber más de una regla DELETE.
Para obtener más información, consulte TTL para columnas y tablas
CONFIGURACIÓN
CounterID y EventDate. Si define una cláusula SAMPLE al seleccionar los datos, ClickHouse devolverá una muestra de datos uniformemente pseudoaleatoria para un subconjunto de usuarios.
El ajuste index_granularity puede omitirse porque 8192 es el valor predeterminado.
Almacenamiento de datos
(CounterID, Date), los datos de la parte se ordenan por CounterID y, dentro de cada CounterID, por Date.
Los datos que pertenecen a distintas particiones se separan en partes diferentes. En segundo plano, ClickHouse fusiona las partes de datos para lograr un almacenamiento más eficiente. Las partes que pertenecen a distintas particiones no se fusionan. El mecanismo de fusión no garantiza que todas las filas con la misma clave primaria estén en la misma parte de datos.
Las partes de datos pueden almacenarse en formato Wide o Compact. En el formato Wide, cada columna se almacena en un archivo independiente dentro de un sistema de archivos; en el formato Compact, todas las columnas se almacenan en un solo archivo. El formato Compact puede usarse para mejorar el rendimiento de inserciones pequeñas y frecuentes.
El formato de almacenamiento de los datos se controla mediante la configuración min_bytes_for_wide_part y min_rows_for_wide_part del motor de tabla. Si el número de bytes o filas de una parte de datos es menor que el valor de la configuración correspondiente, la parte se almacena en formato Compact. De lo contrario, se almacena en formato Wide. Si no se establece ninguna de estas configuraciones, las partes de datos se almacenan en formato Wide.
Cada parte de datos se divide lógicamente en gránulos. Un gránulo es el conjunto de datos indivisible más pequeño que ClickHouse lee al seleccionar datos. ClickHouse no divide filas ni valores, por lo que cada gránulo siempre contiene un número entero de filas. La primera fila de un gránulo se marca con el valor de la clave primaria de esa fila. Para cada parte de datos, ClickHouse crea un archivo de índice que almacena las marcas. Para cada columna, esté o no en la clave primaria, ClickHouse también almacena las mismas marcas. Estas marcas permiten localizar los datos directamente en los archivos de columnas.
El tamaño del gránulo está limitado por la configuración index_granularity e index_granularity_bytes del motor de tabla. El número de filas de un gránulo se encuentra en el intervalo [1, index_granularity], según el tamaño de las filas. El tamaño de un gránulo puede superar index_granularity_bytes si el tamaño de una sola fila es mayor que el valor de la configuración. En este caso, el tamaño del gránulo es igual al tamaño de la fila.
Claves primarias e índices en las consultas
(CounterID, Date). En este caso, la ordenación y el índice pueden ilustrarse de la siguiente manera:
CounterID in ('a', 'h'), el servidor lee los datos en los rangos de marcas[0, 3)y[6, 8).CounterID IN ('a', 'h') AND Date = 3, el servidor lee los datos en los rangos de marcas[1, 3)y[7, 8).Date = 3, el servidor lee los datos en el rango de marcas[1, 10].
index_granularity * 2 filas adicionales en cada bloque de datos.
Los índices dispersos permiten trabajar con una cantidad muy grande de filas en una tabla porque, en la mayoría de los casos, estos índices caben en la RAM del equipo.
ClickHouse no requiere una clave primaria única. Puede insertar varias filas con la misma clave primaria.
Puede usar expresiones de tipo Nullable en las cláusulas PRIMARY KEY y ORDER BY, pero se desaconseja encarecidamente. Para permitir esta funcionalidad, active la opción allow_nullable_key. El principio NULLS_LAST se aplica a los valores NULL en la cláusula ORDER BY.
Selección de una clave primaria
-
Mejorar el rendimiento del índice.
Si la clave primaria es
(a, b), añadir otra columnacmejorará el rendimiento si se cumplen las siguientes condiciones:- Hay consultas con una condición sobre la columna
c. - Son frecuentes rangos de datos largos (varias veces más largos que
index_granularity) con valores idénticos para(a, b). En otras palabras, añadir otra columna te permite omitir rangos de datos bastante largos.
- Hay consultas con una condición sobre la columna
- Mejorar la compresión de los datos. ClickHouse ordena los datos por clave primaria, así que cuanto mayor sea la uniformidad, mejor será la compresión.
- Proporcionar lógica adicional al fusionar partes de datos en los motores CollapsingMergeTree y SummingMergeTree. En este caso, tiene sentido especificar una clave de ordenación distinta de la clave primaria.
SELECT.
Puedes crear una tabla sin clave primaria usando la sintaxis ORDER BY tuple(). En este caso, ClickHouse almacena los datos en el orden de inserción. Si quieres conservar el orden de los datos al insertarlos mediante consultas INSERT ... SELECT, establece max_insert_threads = 1.
Para seleccionar los datos en el orden inicial, usa consultas SELECT de un solo hilo.
Elegir una clave primaria distinta de la clave de ordenación
GROUP BY arbitrarios y filtros por dimensiones. Como SummingMergeTree y AggregatingMergeTree agregan filas con el mismo valor de la clave de ordenación, es natural añadir todas las dimensiones a esta. Como resultado, la expresión de clave consta de una larga lista de columnas, y esta lista debe actualizarse con frecuencia a medida que se añaden nuevas dimensiones.
En este caso, tiene sentido dejar solo unas pocas columnas en la clave primaria para permitir exploraciones de rango eficientes y añadir el resto de las columnas de dimensión a la tupla de la clave de ordenación.
ALTER de la clave de ordenación es una operación ligera porque, cuando se añade simultáneamente una nueva columna a la tabla y a la clave de ordenación, no es necesario modificar las partes de datos existentes. Como la antigua clave de ordenación es un prefijo de la nueva clave de ordenación y no hay datos en la columna recién añadida, en el momento de modificar la tabla los datos quedan ordenados tanto por la antigua como por la nueva clave de ordenación.
Uso de índices y particiones en consultas
SELECT, ClickHouse analiza si puede usarse un índice. Un índice puede usarse si la cláusula WHERE/PREWHERE contiene una expresión (ya sea como uno de los elementos de una conjunción o en su totalidad) que represente una operación de comparación de igualdad o desigualdad, o si contiene IN o LIKE con un prefijo fijo en columnas o expresiones que formen parte de la clave primaria o de la clave de partición, o en determinadas funciones parcialmente repetitivas de estas columnas, o en relaciones lógicas de estas expresiones.
Así, es posible ejecutar rápidamente consultas sobre uno o varios rangos de la clave primaria. En este ejemplo, las consultas serán rápidas cuando se ejecuten para una etiqueta de seguimiento específica, para una etiqueta específica y un intervalo de fechas, para una etiqueta específica y una fecha, para varias etiquetas con un intervalo de fechas, etc.
Veamos el motor configurado de la siguiente manera:
Uso del índice para expresiones deterministas en claves primarias
length(), toDate(), lower(), left(), cityHash64(), toUUID(); a diferencia de now() o rand()). Si la clave primaria contiene expresiones deterministas, ClickHouse puede aplicarlas a los valores constantes de la consulta y usar el resultado para construir condiciones sobre el índice de la clave primaria. Esto permite omitir datos para predicados como =, IN y has.
Un caso de uso habitual es mantener compacta la clave primaria (p. ej., almacenar un hash en lugar de un String largo), sin dejar de permitir que los predicados sobre la columna original usen el índice.
Ejemplo de una clave primaria determinista (pero no inyectiva):
length('alice') (y otras constantes) una sola vez y usa esos valores de longitud para acotar los rangos del índice de clave primaria. Como la longitud de una cadena no es inyectiva, distintos valores de user_id pueden tener la misma longitud, por lo que el índice puede leer gránulos adicionales (falsos positivos). El resultado sigue siendo correcto porque el predicado original (user_id = ..., IN, etc.) se sigue aplicando después de la lectura.
Si la expresión determinista también es inyectiva (distintas entradas no pueden producir la misma salida para los tipos de argumento utilizados), ClickHouse además puede usar eficazmente el índice para las formas negadas: !=, NOT IN y NOT has(...). Por ejemplo, reverse(p) y hex(p) son inyectivas para String.
Ejemplo de una clave primaria inyectiva:
Uso del índice con claves primarias parcialmente monótonas
Índices de omisión de datos
CREATE.
*MergeTree, se pueden especificar índices de omisión de datos.
Estos índices agregan cierta información sobre la expresión especificada en bloques compuestos por granularity_value gránulos (el tamaño del gránulo se especifica mediante la configuración index_granularity en el motor de tabla). Después, estos valores agregados se usan en las consultas SELECT para reducir la cantidad de datos que se leen del disco, omitiendo bloques grandes de datos en los que no puede satisfacerse la consulta where.
La cláusula GRANULARITY puede omitirse; el valor predeterminado de granularity_value es 1.
Ejemplo
Tipos de índices de omisión
MergeTree admite los siguientes tipos de índices de omisión.
Para obtener más información sobre el uso de los índices de omisión para optimizar el rendimiento,
consulta “Comprender los índices de omisión de datos de ClickHouse”.
- índice
MinMax - índice
Set - índice
bloom_filter - índice
ngrambf_v1(Obsoleto) - índice
tokenbf_v1(Obsoleto) - índice
text - índice
vector_similarity
Índice de omisión MinMax
tuple, se almacenan el mínimo y el máximo de cada elemento de la tupla.)
Syntax
Set
max_rows valores únicos de la expresión especificada.
max_rows = 0 significa “almacenar todos los valores únicos”.
Syntax
Filtro de Bloom
Syntax
false_positive_rate puede tomar un valor entre 0 y 1 (de forma predeterminada: 0.025) y especifica la probabilidad de producir un resultado positivo (lo que aumenta la cantidad de datos que deben leerse).
Se admiten los siguientes tipos de datos:
(U)Int*Float*EnumDateDateTimeStringFixedStringArrayLowCardinalityNullableUUIDMap
Tipo de dato JSON: indexación de rutas JSONPara el tipo de dato
JSON, se puede crear un índice bloom filter sobre el conjunto de rutas mediante la función JSONAllPaths. Esto permite omitir gránulos en los que no está presente una ruta JSON consultada. Consulte índices de omisión de datos para JSON para obtener más información.Filtro de Bloom de n-gramas (Obsoleto)
Con la disponibilidad general (GA) del índice
text a partir de la versión 26.2 de ClickHouse, el índice ngrambf_v1 ya no se recomienda para la búsqueda de texto completo.Consulte la página “Búsqueda de texto completo con índices de texto” para obtener más información.Syntax
| Parámetro | Descripción |
|---|---|
n | tamaño del ngram |
size_of_bloom_filter_in_bytes | Tamaño del filtro de Bloom en bytes. Aquí se puede usar un valor grande, por ejemplo, 256 o 512, porque se comprime bien). |
number_of_hash_functions | Número de funciones hash usadas en el filtro de Bloom. |
random_seed | Semilla para las funciones hash del filtro de Bloom. |
ngrambf_v1, puede usar las siguientes funciones definidas por el usuario (UDFs).
UDFs for ngrambf_v1
total_number_of_all_gramsprobability_of_false_positives
4300 ngrams en el gránulo y se espera que los falsos positivos sean inferiores a 0.0001.
Los demás parámetros pueden estimarse ejecutando las siguientes consultas:
Filtro de Bloom de tokens
Con la disponibilidad general (GA) del índice
text a partir de ClickHouse 26.2, el índice tokenbf_v1 ya no se recomienda para la búsqueda de texto completo.Consulta la página “Búsqueda de texto completo con índices de texto” para más detalles.Syntax
Filtro de Bloom de gramas dispersas
ngrambf_v1, pero utiliza tokens de gramas dispersas en lugar de ngrams.
Syntax
Índice de texto
Similitud vectorial
Compatibilidad con funciones
WHERE contienen llamadas a funciones que operan sobre columnas. Si la columna forma parte de un índice, ClickHouse intenta usarlo al evaluar las funciones. ClickHouse admite distintos subconjuntos de funciones para utilizar índices.
Los índices de tipo set pueden ser utilizados por todas las funciones. Los demás tipos de índices son compatibles de la siguiente manera:
| Función (operador) / índice | clave primaria | minmax | ngrambf_v1 | tokenbf_v1 | bloom_filter | sparse_grams | text |
|---|---|---|---|---|---|---|---|
| igual (=, ==) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| notEquals(!=, <>) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ |
| like | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ | ✔ |
| notLike | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ | ✗ |
| match | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ | ✔ |
| startsWith | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ | ✔ |
| endsWith | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ | ✔ |
| multiSearchAny | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ |
| in | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| notIn | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ |
less (<) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
greater (>) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
lessOrEquals (<=) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
greaterOrEquals (>=) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
| empty | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
| notEmpty | ✗ | ✔ | ✗ | ✗ | ✗ | ✔ | ✗ |
| has | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| hasAny | ✗ | ✗ | ✔ | ✔ | ✔ | ✔ | ✗ |
| hasAll | ✗ | ✗ | ✔ | ✔ | ✔ | ✔ | ✗ |
| hasToken | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | ✔ |
| hasTokenOrNull | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | ✔ |
hasTokenCaseInsensitive (*) | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ |
hasTokenCaseInsensitiveOrNull (*) | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ |
| hasAnyTokens | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ |
| hasAllTokens | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ |
| pointInPolygon | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
| mapContains (mapContainsKey) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ |
| mapContainsKeyLike | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ |
| mapContainsValue | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ |
| mapContainsValueLike | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ |
ngrambf_v1 para la optimización de consultas.
(*) Para que hasTokenCaseInsensitive y hasTokenCaseInsensitiveOrNull sean eficaces, el índice tokenbf_v1 debe crearse sobre datos en minúsculas; por ejemplo, INDEX idx (lower(str_col)) TYPE tokenbf_v1(512, 3, 0).
Los filtros de Bloom pueden producir falsos positivos, por lo que los índices
ngrambf_v1, tokenbf_v1, sparse_grams y bloom_filter no pueden usarse para optimizar consultas en las que se espera que el resultado de una función sea falso.Por ejemplo:- Se puede optimizar:
s LIKE '%test%'NOT s NOT LIKE '%test%'s = 1NOT s != 1startsWith(s, 'test')
- No se puede optimizar:
NOT s LIKE '%test%'s NOT LIKE '%test%'NOT s = 1s != 1NOT startsWith(s, 'test')
Proyecciones
Al implementar proyecciones, también debes tener en cuenta la configuración force_optimize_projection.
SELECT que utilizan el modificador FINAL.
Consulta de proyección
Índices de proyección
_part_offset, es decir, SELECT _part_offset ORDER BY <index_expr>.
Sintaxis
Tipos de índices
- basic: equivalente a un índice normal de MergeTree sobre la expresión.
Almacenamiento de proyecciones
MergeTree anónima. La tabla queda determinada por la consulta de definición de la proyección. Si hay una cláusula GROUP BY, el motor de almacenamiento subyacente pasa a ser AggregatingMergeTree, y todas las funciones de agregación se convierten en AggregateFunction. Si hay una cláusula ORDER BY, la tabla MergeTree la usa como expresión de clave primaria. Durante el proceso de combinación, la parte de la proyección se combina mediante la rutina de combinación de su almacenamiento. La suma de comprobación de la parte de la tabla principal se combina con la parte de la proyección. Otras tareas de mantenimiento son similares a las de los índices de omisión.
Análisis de consultas
- Compruebe si la proyección puede usarse para responder a la consulta dada; es decir, si genera el mismo resultado que consultar la tabla base.
- Seleccione la mejor coincidencia factible, la que implique leer la menor cantidad de gránulos.
- El pipeline de consulta que usa proyecciones será diferente del que usa las partes originales. Si la proyección no está presente en algunas partes, podemos añadir un pipeline para «proyectarla» sobre la marcha.
Acceso concurrente a los datos
TTL para columnas y tablas
TTL se puede definir para toda la tabla y para cada columna individual. El TTL a nivel de tabla también puede especificar la lógica para mover datos automáticamente entre discos y volúmenes, o para recomprimir partes en las que todos los datos hayan expirado.
Las expresiones deben dar como resultado un tipo de dato Date, Date32, DateTime o DateTime64.
Sintaxis
Establecer el tiempo de vida para una columna:
interval, utilice los operadores de intervalo de tiempo, por ejemplo:
TTL de columna
TTL no puede usarse en las columnas clave.
Ejemplos
Crear una tabla con TTL:
Añadir TTL a una columna de una tabla existente
Modificación del TTL de la columna
TTL de tabla
TTL.
DELETE- elimina las filas expiradas (acción predeterminada);RECOMPRESS codec_name- recompime la parte de datos concodec_name;TO DISK 'aaa'- mueve la parte al discoaaa;TO VOLUME 'bbb'- mueve la parte al discobbb;GROUP BY- agrega las filas expiradas.
DELETE puede usarse junto con la cláusula WHERE para eliminar solo algunas de las filas expiradas en función de una condición de filtrado:
GROUP BY debe ser un prefijo de la clave primaria de la tabla.
Si una columna no forma parte de la expresión GROUP BY y no se establece explícitamente en la cláusula SET, la fila de resultado contiene un valor cualquiera de las filas agrupadas (como si se le aplicara la función de agregación any).
Ejemplos
Crear una tabla con TTL:
Modificación del TTL de la tabla:
Creación de una tabla en la que las filas expiradas se recomprimen:
x contiene el valor máximo de entre las filas agrupadas, y — el valor mínimo, y d — un valor cualquiera de las filas agrupadas.
Eliminación de datos expirados
TTL vencido se eliminan cuando ClickHouse fusiona partes de datos.
Cuando ClickHouse detecta que los datos han vencido, realiza una fusión no programada. Para controlar la frecuencia de estas fusiones, puede establecer merge_with_ttl_timeout. Si el valor es demasiado bajo, se realizarán muchas fusiones no programadas que pueden consumir muchos recursos.
Si ejecuta la consulta SELECT entre fusiones, puede obtener datos vencidos. Para evitarlo, use la consulta OPTIMIZE antes de SELECT.
Vea también
- ajuste ttl_only_drop_parts
Tipos de disco
s3para S3 y MinIOgcspara GCSblob_storage_diskpara Azure Blob Storagehdfspara HDFSwebpara acceso de solo lectura desde la webcachepara caché locals3_plainpara copias de seguridad en S3s3_plain_rewritablepara tablas inmutables no replicadas en S3
Uso de varios dispositivos de bloque para almacenar datos
Introducción
MergeTree pueden almacenar datos en varios dispositivos de bloques. Por ejemplo, esto puede resultar útil cuando los datos de una determinada tabla se dividen implícitamente en “calientes” y “fríos”. Se consulta regularmente a los datos más recientes, pero solo requieren una pequeña cantidad de espacio. En cambio, los datos históricos de cola larga se consultan rara vez. Si hay varios discos disponibles, los datos “calientes” pueden ubicarse en discos rápidos (por ejemplo, SSD NVMe o en memoria), mientras que los datos “fríos” pueden almacenarse en discos relativamente lentos (por ejemplo, HDD).
Esto se aplica a todos los tipos de disco, incluidos S3 y otros discos de almacenamiento de objetos. Por ejemplo, puede distribuir los datos entre varios buckets de S3 dentro de un único volumen, o crear políticas por niveles que muevan datos de discos locales a S3. Consulte Uso de discos S3 con varios volúmenes para obtener más información.
Una parte de datos es la unidad mínima que puede moverse en las tablas con motor MergeTree. Los datos que pertenecen a una parte se almacenan en un solo disco. Las partes de datos pueden moverse entre discos en segundo plano (según la configuración del usuario), así como mediante las consultas ALTER.
Términos
- Disco — Dispositivo de bloque montado en el sistema de archivos.
- Disco predeterminado — Disco que almacena los datos en la ruta especificada en la configuración del servidor path.
- Volumen — Conjunto ordenado de discos equivalentes (similar a JBOD).
- Política de almacenamiento — Conjunto de volúmenes y reglas para mover datos entre ellos.
storage_policy de las tablas de la familia de motores MergeTree.
Configuración
<storage_configuration>, en un archivo del directorio config.d.
Estructura de la configuración:
<disk_name_N>— Nombre del disco. Los nombres deben ser diferentes para todos los discos.path— ruta en la que el servidor almacenará los datos (carpetasdatayshadow); debe terminar con ’/’.keep_free_space_bytes— la cantidad de espacio libre en disco que se debe reservar.
policy_name_N— Nombre de la política. Los nombres de las políticas deben ser únicos.volume_name_N— Nombre del volumen. Los nombres de los volúmenes deben ser únicos.disk— un disco dentro de un volumen.max_data_part_size_bytes— el tamaño máximo de una parte que puede almacenarse en cualquiera de los discos del volumen. Si se estima que el tamaño de una parte fusionada será mayor quemax_data_part_size_bytes, esa parte se escribirá en el siguiente volumen. Básicamente, esta funcionalidad permite mantener las partes nuevas o pequeñas en un volumen rápido (SSD) y moverlas a un volumen frío (HDD) cuando alcanzan un tamaño grande. No use esta configuración si su política tiene un solo volumen.move_factor— cuando la cantidad de espacio disponible cae por debajo de este factor, los datos comienzan a moverse automáticamente al siguiente volumen, si existe (de forma predeterminada, 0.1). ClickHouse ordena las partes existentes por tamaño, de mayor a menor, y selecciona las partes cuyo tamaño total sea suficiente para cumplir la condición demove_factor. Si el tamaño total de todas las partes es insuficiente, se moverán todas las partes.perform_ttl_move_on_insert— Desactiva el movimiento TTL en INSERT de partes de datos. De forma predeterminada (si está habilitado), si insertamos una parte de datos que ya ha expirado según la regla de movimiento TTL, se envía inmediatamente a un volumen/disco declarado en la regla de movimiento. Esto puede ralentizar significativamente la inserción si el volumen/disco de destino es lento (por ejemplo, S3). Si está deshabilitado, la parte de datos ya expirada se escribe en un volumen predeterminado y, acto seguido, se mueve al volumen TTL.load_balancing- Política de equilibrio entre discos,round_robinoleast_used.least_used_ttl_ms- Configura el tiempo de espera (en milisegundos) para actualizar el espacio disponible en todos los discos (0- actualizar siempre,-1- no actualizar nunca, el valor predeterminado es60000). Tenga en cuenta que, si el disco solo puede ser utilizado por ClickHouse y no está sujeto a un cambio de tamaño o reducción en línea del sistema de archivos, puede usar-1; en todos los demás casos no se recomienda, ya que con el tiempo provocará una distribución incorrecta del espacio.prefer_not_to_merge— No debería usar esta configuración. Desactiva la fusión de partes de datos en este volumen (esto es perjudicial y degrada el rendimiento). Cuando esta configuración está habilitada (no lo haga), no se permite fusionar datos en este volumen (lo cual es malo). Esto permite (pero no lo necesita) controlar (si quiere controlar algo, está cometiendo un error) cómo funciona ClickHouse con discos lentos (pero ClickHouse lo sabe mejor, así que por favor no use esta configuración).volume_priority— Define la prioridad (orden) en que se llenan los volúmenes. Un valor menor significa una prioridad más alta. Los valores del parámetro deben ser números naturales y, en conjunto, cubrir el rango de 1 a N (incluida la prioridad más baja) sin omitir ningún número.- Si todos los volúmenes están etiquetados, se priorizan en el orden indicado.
- Si solo algunos volúmenes están etiquetados, los que no tienen etiqueta tienen la prioridad más baja y se priorizan en el orden en que están definidos en la configuración.
- Si ningún volumen está etiquetado, su prioridad se establece de acuerdo con el orden en que se declaran en la configuración.
- Dos volúmenes no pueden tener el mismo valor de prioridad.
hdd_in_order implementa el enfoque round-robin. Por lo tanto, esta política define un único volumen (single) y las partes de datos se almacenan en todos sus discos en orden circular. Esta política puede resultar bastante útil si hay varios discos similares montados en el sistema, pero no se ha configurado RAID. Ten en cuenta que cada unidad de disco por separado no es fiable, por lo que quizá quieras compensarlo con un factor de replicación de 3 o más.
Si hay distintos tipos de discos disponibles en el sistema, se puede usar en su lugar la política moving_from_ssd_to_hdd. El volumen hot consta de un disco SSD (fast_ssd), y el tamaño máximo de una parte que puede almacenarse en este volumen es de 1GB. Todas las partes cuyo tamaño supere 1GB se almacenarán directamente en el volumen cold, que contiene un disco HDD disk1.
Además, cuando el disco fast_ssd supere el 80% de ocupación, los datos se transferirán a disk1 mediante un proceso en segundo plano.
El orden en que se enumeran los volúmenes dentro de una política de almacenamiento es importante si al menos uno de los volúmenes listados no tiene un parámetro volume_priority explícito.
Una vez que un volumen se llena en exceso, los datos se mueven al siguiente. El orden en que se enumeran los discos también es importante, porque los datos se almacenan en ellos por turnos.
Al crear una tabla, se le puede aplicar una de las políticas de almacenamiento configuradas:
default supone el uso de un solo volumen, que consta de un único disco especificado en <path>.
Puede cambiar la política de almacenamiento después de crear la tabla mediante la consulta [ALTER TABLE … MODIFY SETTING]; la nueva política debe incluir todos los discos y volúmenes anteriores con los mismos nombres.
El número de hilos que realizan movimientos en segundo plano de partes de datos puede cambiarse con la configuración background_move_pool_size.
Detalles
MergeTree, los datos llegan al disco de distintas maneras:
- Como resultado de una operación de insert (consulta
INSERT). - Durante las fusiones en segundo plano y las mutaciones.
- Al descargarlos desde otra réplica.
- Como resultado de la congelación de particiones ALTER TABLE … FREEZE PARTITION.
- Se elige el primer volumen (en el orden de definición) que tenga suficiente espacio en disco para almacenar una parte (
unreserved_space > current_part_size) y permita almacenar partes de un tamaño determinado (max_data_part_size_bytes > current_part_size). - Dentro de este volumen, se elige el disco que sigue al que se utilizó para almacenar el fragmento de datos anterior y que tiene un espacio libre mayor que el tamaño de la parte (
unreserved_space - keep_free_space_bytes > current_part_size).
move_factor), según el orden en que los volúmenes se declaran en el archivo de configuración.
Los datos nunca se transfieren del último al primero. Se pueden usar las tablas del sistema system.part_log (campo type = MOVE_PART) y system.parts (campos path y disk) para supervisar los movimientos en segundo plano. Además, la información detallada puede encontrarse en los logs del servidor.
El usuario puede forzar el movimiento de una parte o una partición de un volumen a otro mediante la consulta ALTER TABLE … MOVE PART|PARTITION … TO VOLUME|DISK …; se tienen en cuenta todas las restricciones de las operaciones en segundo plano. La consulta inicia el movimiento por sí sola y no espera a que las operaciones en segundo plano se completen. El usuario recibirá un mensaje de error si no hay suficiente espacio libre disponible o si no se cumple alguna de las condiciones requeridas.
El movimiento de datos no interfiere con la replicación de datos. Por lo tanto, se pueden especificar distintas políticas de almacenamiento para la misma tabla en distintas réplicas.
Tras completarse las fusiones en segundo plano y las mutaciones, las partes antiguas se eliminan solo después de que transcurra una determinada cantidad de tiempo (old_parts_lifetime).
Durante este tiempo, no se mueven a otros volúmenes ni discos. Por lo tanto, hasta que las partes se eliminen definitivamente, se siguen teniendo en cuenta para evaluar el espacio en disco ocupado.
El usuario puede asignar nuevas partes grandes a distintos discos de un volumen JBOD de forma equilibrada mediante la configuración min_bytes_to_rebalance_partition_over_jbod.
Uso de almacenamiento externo para almacenar datos
S3, AzureBlobStorage y HDFS mediante un disco de tipo s3, azure_blob_storage o hdfs, respectivamente. Consulta la configuración de las opciones de almacenamiento externo para obtener más información.
Ejemplo de S3 como almacenamiento externo mediante un disco de tipo s3.
Marcado de configuración:
Uso de discos S3 con múltiples volúmenes
Al usar
use_environment_credentials para la autenticación con S3, las credenciales del entorno (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) se comparten entre todos los discos S3. No es posible usar credenciales del entorno diferentes para distintos discos. Si necesita credenciales diferentes para cada disco S3, use en su lugar la configuración explícita de access_key_id y secret_access_key para cada disco.table_disk = true con un disco local para la tabla). Consulte refresh_parts_interval and table_disk.
configuración de cachéLas versiones 22.3 a 22.7 de ClickHouse usan una configuración de caché distinta; consulte using local cache si usa una de esas versiones.
Columnas virtuales
_part— Nombre de una parte._part_index— Índice secuencial de la parte en el resultado de la consulta._part_starting_offset— Fila inicial acumulada de la parte en el resultado de la consulta._part_offset— Número de fila dentro de la parte._part_granule_offset— Número de gránulo dentro de la parte._partition_id— Nombre de una partición._part_uuid— Identificador único de la parte (si está habilitada la opción de MergeTreeassign_part_uuids)._part_data_version— Versión de los datos de la parte (ya sea el número mínimo de bloque o la versión de la mutación)._partition_value— Valores (una tupla) de una expresiónpartition by._sample_factor— Factor de muestreo (de la consulta)._block_number— Número original del bloque de la fila que se asignó al insertar, conservado en las fusiones cuando está habilitada la opciónenable_block_number_column._block_offset— Número original de la fila dentro del bloque que se asignó al insertar, conservado en las fusiones cuando está habilitada la opciónenable_block_offset_column._disk_name— Nombre del disco utilizado para el almacenamiento.
Estadísticas de columnas
CREATE para tablas de la familia *MergeTree*:
ALTER:
set use_statistics = 1.
Poda de partes con estadísticas
use_statistics_for_part_pruning está habilitado, las estadísticas pueden usarse para la poda de partes.
Actualmente, las estadísticas MinMax y NullCount admiten la poda de partes. Cuando se definen estadísticas MinMax en una columna, ClickHouse registra los valores mínimo y máximo de esa columna en cada parte. Cuando se definen estadísticas NullCount en una columna Nullable, ClickHouse registra el número de valores NULL en cada parte, lo que permite la poda basada en predicados IS NULL / IS NOT NULL y mejora la precisión de la poda de filtros de rango en columnas con valores NULL.
La poda de partes permite omitir la lectura de partes de datos completas cuando la condición de filtro de la consulta no puede coincidir con ninguna fila de esa parte.
Ejemplo:
Tipos disponibles de estadísticas de columnas
-
MinMaxEl valor mínimo y máximo de la columna, lo que permite estimar la selectividad de los filtros por rango en columnas numéricas. Sintaxis:minmax -
TDigestResúmenes TDigest que permiten calcular percentiles aproximados (por ejemplo, el percentil 90) para columnas numéricas. Sintaxis:tdigest -
UniqResúmenes HyperLogLog que permiten estimar cuántos valores distintos contiene una columna. Sintaxis:uniq -
NullCountLleva un seguimiento del número de valoresNULLen columnasNullable. Se usa para estimar con precisión la selectividad de los predicadosIS NULL/IS NOT NULLen la optimización de PREWHERE y permite la poda de partes según la presencia de NULL. Sintaxis:nullcount -
CountMinResúmenes CountMin que proporcionan un recuento aproximado de la frecuencia de cada valor de una columna. Sintaxiscountmin
Tipos de datos compatibles
| (U)Int*, Float*, Decimal(), Date, Boolean, Enum* | String o FixedString | Nullable() / LowCardinality(Nullable()) | |
|---|---|---|---|
| CountMin | ✔ | ✔ | ✗ |
| MinMax | ✔ | ✗ | ✔ |
| NullCount | ✗ | ✗ | ✔ |
| TDigest | ✔ | ✗ | ✔ |
| Uniq | ✔ | ✔ | ✔ |
Operaciones admitidas
| Filtros de igualdad (==) | Filtros de rango (>, >=, <, <=) | IS NULL / IS NOT NULL | |
|---|---|---|---|
| CountMin | ✔ | ✗ | ✗ |
| MinMax | ✗ | ✔ | ✗ |
| NullCount | ✗ | ✗ | ✔ |
| TDigest | ✗ | ✔ | ✗ |
| Uniq | ✔ | ✗ | ✗ |
Configuración por columna
max_compress_block_size— Tamaño máximo de los bloques de datos sin comprimir antes de comprimirlos para escribirlos en una tabla.min_compress_block_size— Tamaño mínimo de los bloques de datos sin comprimir necesario para la compresión al escribir la siguiente marca.
- Eliminar
SETTINGSde la declaración de la columna:
- Modifique una configuración:
- Restablece una o varias configuraciones; también elimina la declaración de configuración en la expresión de la columna de la consulta CREATE de la tabla.