> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Un motor de tabla que almacena series temporales, es decir, un conjunto de valores asociados a marcas de tiempo y etiquetas (o labels).

# motor de tabla TimeSeries

export const PrivatePreviewBadge = () => {
  return <div className="privatePreviewBadge">
            <div className="privatePreviewIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M5.33301 6.66667V4.66667V4.66667C5.33301 3.194 6.52701 2 7.99967 2V2C9.47234 2 10.6663 3.194 10.6663 4.66667V4.66667V6.66667" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path d="M8.00033 9.33337V11.3334" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path fillRule="evenodd" clipRule="evenodd" d="M11.333 14H4.66634C3.92967 14 3.33301 13.4033 3.33301 12.6666V7.99996C3.33301 7.26329 3.92967 6.66663 4.66634 6.66663H11.333C12.0697 6.66663 12.6663 7.26329 12.6663 7.99996V12.6666C12.6663 13.4033 12.0697 14 11.333 14Z" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            {'Vista previa privada'}
        </div>;
};

<PrivatePreviewBadge />

Un motor de tabla que almacena series temporales, es decir, un conjunto de valores asociados a marcas de tiempo y etiquetas (o labels):

```sql theme={null}
metric_name1[tag1=value1, tag2=value2, ...] = {timestamp1: value1, timestamp2: value2, ...}
metric_name2[...] = ...
```

<Info>
  Esta es una funcionalidad de vista previa privada que puede cambiar de formas incompatibles con versiones anteriores en futuras versiones.
  Habilite el uso del motor de tabla TimeSeries
  con el SETTING `enable_time_series_table`.
  Ejecute el comando `set enable_time_series_table = 1`.
</Info>

<Note>
  El motor de tabla `TimeSeries` está disponible en ClickHouse Cloud como funcionalidad de vista previa privada.
  Los servicios que participan en la vista previa privada ya tienen configurado el
  SETTING `enable_time_series_table`. Los demás servicios de ClickHouse Cloud
  no cuentan con esta configuración, y no es posible habilitar el motor por su cuenta en
  dichos servicios.
</Note>

## Sintaxis

```sql theme={null}
CREATE TABLE name [(columns)] ENGINE=TimeSeries
[SETTINGS var1=value1, ...]
[SAMPLES db.samples_table_name | [SAMPLES INNER COLUMNS (...)] [SAMPLES INNER ENGINE engine(arguments)]]
[RECENT SAMPLES db.recent_samples_table_name | [RECENT SAMPLES INNER COLUMNS (...)] [RECENT SAMPLES INNER ENGINE engine(arguments)]]
[TAGS db.tags_table_name | [TAGS INNER COLUMNS (...)] [TAGS INNER ENGINE engine(arguments)]]
[METRIC FAMILIES db.metric_families_table_name | [METRIC FAMILIES INNER COLUMNS (...)] [METRIC FAMILIES INNER ENGINE engine(arguments)]]
```

<Note>
  La palabra clave `SAMPLES` tiene el alias `DATA`, y la palabra clave `METRIC FAMILIES` tiene el alias `METRICS`; ambos se mantienen por compatibilidad con versiones anteriores.
  La definición de una tabla de una [version](#schema-versioning) anterior a 4 se escribe con `METRICS`, de modo que un servidor más antiguo pueda leerla.
</Note>

## Uso

Es más fácil empezar con la configuración predeterminada (se puede crear una tabla `TimeSeries` sin especificar una lista de columnas):

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
```

A continuación, esta tabla puede utilizarse con los siguientes protocolos (debe asignarse un puerto en la configuración del servidor):

* [prometheus remote-write](/es/concepts/features/interfaces/prometheus#remote-write)
* [prometheus remote-read](/es/concepts/features/interfaces/prometheus#remote-read)

### Columnas externas

Las columnas de una tabla TimeSeries se generan automáticamente. Son columnas externas: no almacenan datos, solo proporcionan la interfaz para SELECT/INSERT. Los datos reales se almacenan en las [tablas de destino](#target-tables). Aquí está la lista de las columnas externas:

| Nombre | Tipo | Descripción |
| - | - | - |
| `metric_name` | `String` | El nombre de la métrica |
| `tags` | `Map(String, String)` | Mapa de etiquetas (labels) de la serie temporal |
| `samples` | `Array(Tuple(DateTime64(3), Float64))` de forma predeterminada | Array de pares (timestamp, valor) de una serie temporal. Los tipos del timestamp y del elemento escalar de la tupla pueden derivarse de la declaración `INNER COLUMNS` de las sample (consulta [Especificación de columnas externas](#specifying-outer-columns)). La columna se denomina `time_series` en las tablas de la [version](#schema-versioning) 2 y anteriores |
| `metric_family` | `String` | El nombre de la familia de métricas (para los metadatos de métricas) |
| `type` | `String` | El tipo de la métrica (p. ej., "counter", "gauge") |
| `unit` | `String` | La unidad de la métrica |
| `help` | `String` | La descripción de la métrica |

Ejemplo:

```sql theme={null}
INSERT INTO my_table (metric_name, tags, samples) VALUES
    ('cpu_usage', {'job': 'node_exporter', 'instance': 'host1:9100'},
     [(toDateTime64('2024-01-01 00:00:00', 3), 0.5), (toDateTime64('2024-01-01 00:01:00', 3), 0.7)])
```

Se permite que `metric_name` esté vacío durante la inserción, lo que significa que el nombre de la métrica se especifica en `tags` con `__name__`, por ejemplo:

```sql theme={null}
INSERT INTO my_table (tags, samples) VALUES
    ({'__name__': 'cpu_usage', 'job': 'test'},
     [(toDateTime64('2024-01-01 00:00:00', 3), 0.5)])
```

Para insertar metadatos de métricas, insértelos en las columnas `metric_family`, `type`, `unit` y `help`:

```sql theme={null}
INSERT INTO my_table (metric_name, tags, samples, metric_family, type, unit, help) VALUES
    ('http_requests_total', {'method': 'GET'}, [(now64(), 100.0)],
     'http_requests_total', 'counter', 'requests', 'Total HTTP requests')
```

### Especificación de columnas externas

La columna externa `samples` se puede incluir explícitamente en una sentencia `CREATE TABLE` para sobrescribir su tipo predeterminado `Array(Tuple(DateTime64(3), Float64))` (también se acepta su nombre anterior `time_series`). ClickHouse extrae de la tupla los tipos de marca de tiempo y escalares, y los propaga a la tabla interna de muestras:

```sql theme={null}
CREATE TABLE my_table (samples Array(Tuple(UInt32, Float32))) ENGINE=TimeSeries
```

Esto equivale a declarar directamente los tipos de las columnas `timestamp` y `value` en la cláusula `INNER COLUMNS` de samples:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp UInt32 CODEC(Delta, T64, ZSTD(3)), value Float32 CODEC(ALP, ZSTD(3)))
```

Si ambas formas se usan en la misma sentencia `CREATE TABLE`, los tipos declarados deben coincidir.

## Tablas de destino

Una tabla `TimeSeries` no tiene datos propios; todo se almacena en sus tablas de destino.
Esto es similar al funcionamiento de una [vista materializada](/es/reference/statements/create/view#materialized-view),
con la diferencia de que una vista materializada tiene una sola tabla de destino,
mientras que una tabla `TimeSeries` tiene tres tablas de destino obligatorias llamadas [samples](#samples-table), [etiqueta](#tags-table) y [familia de métricas](#metric-families-table),
y una tabla de destino opcional [muestra reciente](#recent-samples-table) que está habilitada de forma predeterminada
(consulte la configuración [recent\_samples\_ttl\_seconds](#settings)).

Las tablas de destino pueden especificarse explícitamente en la consulta `CREATE TABLE`
o el motor de tabla `TimeSeries` puede generar automáticamente tablas de destino internas.

Las filas insertadas en una tabla `TimeSeries` se transforman, se dividen en bloques y se insertan en estas tablas de destino.

Las tablas de destino son las siguientes:

### Tabla samples

La tabla *samples* contiene series temporales asociadas a algún identificador.

La tabla *samples* debe tener las siguientes columnas:

| Nombre | ¿Obligatorio? | Tipo predeterminado | Tipos posibles | Descripción |
| - | - | - | - | - |
| `id` | \[x] | `Tuple(UInt64, LowCardinality(UUID))` | cualquiera | Identifica una combinación de nombres de métricas y etiquetas |
| `timestamp` | \[x] | `DateTime64(3)` | `DateTime64(X)` | Un instante temporal |
| `value` | \[x] | `Float64` | `Float32` o `Float64` | Un valor asociado al `timestamp` |

Las columnas que crea el propio motor utilizan códecs de compresión para series temporales:
`timestamp CODEC(Delta, T64, ZSTD(3))` y `value CODEC(ALP, ZSTD(3))`. Las marcas de tiempo casi monotónicas apenas
se comprimen con códecs genéricos y, de lo contrario, pueden representar la mayor parte del tamaño en disco de la tabla samples.
El motor habilita `ALP` para sus tablas internas de samples y muestras recientes sin requerir que se establezca `enable_alp_codec`.
Consulte también [Ajustar los tipos de las columnas](#adjusting-column-types).

### Tabla de muestras recientes

La tabla de *muestras recientes* es opcional y está habilitada de forma predeterminada (véase el ajuste [recent\_samples\_ttl\_seconds](#settings);
si se establece en cero, la tabla se deshabilita). Contiene una copia de las muestras más recientes que el TTL definido por ese ajuste,
y debe tener las mismas columnas que la tabla [samples](#samples-table).
La columna generada `timestamp` usa `CODEC(Delta, T64, ZSTD(3))`,
y la columna generada `value` usa `CODEC(ALP, ZSTD(3))`.

Cada muestra insertada se escribe tanto en la tabla de muestras como en la tabla de muestras recientes.
Las consultas cuyo rango temporal se ajusta a la ventana del TTL leen de la tabla de muestras recientes en lugar de la tabla principal de muestras,
ya que es mucho más pequeña (esto se puede deshabilitar con el ajuste a nivel de consulta `time_series_prefer_recent_samples_table`).

El TTL de la tabla interna de muestras recientes siempre se deriva del ajuste [recent\_samples\_ttl\_seconds](#settings).

### Tabla de etiquetas

La tabla *etiquetas* contiene identificadores calculados para cada combinación de un nombre de métrica y etiquetas.

La tabla *etiquetas* debe tener las siguientes columnas:

| Nombre | ¿Obligatorio? | Tipo predeterminado | Tipos posibles | Descripción |
| - | - | - | - | - |
| `id` | \[x] | `Tuple(UInt64, LowCardinality(UUID))` | cualquiera (debe coincidir con el tipo de `id` de la tabla [samples](#samples-table)) | Un `id` identifica una combinación de un nombre de métrica y etiquetas. La expresión DEFAULT especifica cómo calcular ese identificador |
| `metric_name` | \[x] | `LowCardinality(String)` | `String` o `LowCardinality(String)` | El nombre de una métrica |
| `<tag_value_column>` | \[ ] | `String` | `String` o `LowCardinality(String)` o `LowCardinality(Nullable(String))` | El valor de una etiqueta específica; el nombre de la etiqueta y el nombre de la columna correspondiente se especifican en el SETTING [tags\_to\_columns](#settings) |
| `tags` | \[x] | `Map(LowCardinality(String), String)` | `Map(String, String)` o `Map(LowCardinality(String), String)` o `Map(LowCardinality(String), LowCardinality(String))` | Mapa de todas las etiquetas, incluida la etiqueta `__name__`, que contiene el nombre de una métrica, y las etiquetas cuyos nombres se enumeran en el SETTING [tags\_to\_columns](#settings). Las tablas creadas por versiones anteriores de ClickHouse almacenaban en esta columna solo las etiquetas sin columnas dedicadas y sin el nombre de la métrica; la lectura gestiona ambos casos |
| `min_time` | \[ ] | `Nullable(DateTime64(3))` | `DateTime64(X)` o `Nullable(DateTime64(X))` | Marca de tiempo mínima de la serie temporal con ese `id`. La columna se crea si [store\_min\_time\_and\_max\_time](#settings) es `true` |
| `max_time` | \[ ] | `Nullable(DateTime64(3))` | `DateTime64(X)` o `Nullable(DateTime64(X))` | Marca de tiempo máxima de la serie temporal con ese `id`. La columna se crea si [store\_min\_time\_and\_max\_time](#settings) es `true` |

Las nuevas tablas internas de etiquetas de la [versión](#schema-versioning) 5 y posteriores con un motor de la familia `MergeTree` tienen un índice de texto invertido sobre `tags`:
`INDEX tags_idx tags TYPE text(tokenizer = 'keyValuePairs')`. Acelera las coincidencias exactas de etiquetas como
`{job="api"}` en PromQL al buscar conjuntamente la clave y el valor. Las comparaciones con una cadena vacía también
coinciden con etiquetas ausentes y no utilizan este índice.

Los índices explícitos declarados en `TAGS INNER COLUMNS` sustituyen al índice predeterminado. Las tablas existentes y las tablas de etiquetas externas
conservan sus índices; añade y materializa el índice en su tabla de destino de etiquetas para habilitarlo.

### Tabla de familias de métricas

La tabla *familias de métricas* contiene información sobre las familias de métricas recopiladas, sus tipos y sus descripciones.
Una familia de métricas es un grupo de métricas con el mismo nombre (el tag `__name__`) y el mismo tipo; por ejemplo, un histogram es una familia de métricas que consta de múltiples métricas.

La tabla *familias de métricas* debe tener las siguientes columnas:

| Nombre | ¿Obligatorio? | Tipo predeterminado | Tipos posibles | Descripción |
| - | - | - | - | - |
| `metric_family_name` | \[x] | `String` | `String` o `LowCardinality(String)` | El nombre de una familia de métricas |
| `type` | \[x] | `LowCardinality(String)` | `String` o `LowCardinality(String)` | El tipo de una familia de métricas; uno de "counter", "gauge", "summary", "stateset", "histogram", "gaugehistogram" |
| `unit` | \[x] | `LowCardinality(String)` | `String` o `LowCardinality(String)` | La unidad utilizada en una métrica |
| `help` | \[x] | `String` | `String` o `LowCardinality(String)` | La descripción de una métrica |

## Creación

Existen varias formas de crear una table con el motor de tabla `TimeSeries`.
La sentencia más sencilla

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
```

en realidad creará la siguiente tabla (puedes comprobarlo ejecutando `SHOW CREATE TABLE my_table`):

```sql theme={null}
CREATE TABLE my_table
(
    `metric_name` String,
    `tags` Map(String, String),
    `samples` Array(Tuple(DateTime64(3), Float64)),
    `metric_family` String,
    `type` String,
    `unit` String,
    `help` String
)
ENGINE = TimeSeries
SETTINGS version = 5, recent_samples_ttl_seconds = 345600
SAMPLES INNER COLUMNS
(
    `id` Tuple(UInt64, LowCardinality(UUID)),
    `timestamp` DateTime64(3) CODEC(Delta, T64, ZSTD(3)),
    `value` Float64 CODEC(ALP, ZSTD(3))
)
SAMPLES INNER ENGINE = MergeTree ORDER BY (id, timestamp) SETTINGS index_granularity = 32768
RECENT SAMPLES INNER COLUMNS
(
    `id` Tuple(UInt64, UUID),
    `timestamp` DateTime64(3) CODEC(Delta, T64, ZSTD(3)),
    `value` Float64 CODEC(ALP, ZSTD(3))
)
RECENT SAMPLES INNER ENGINE = MergeTree PARTITION BY toStartOfInterval(toDateTime(timestamp), toIntervalHour(5)) ORDER BY (id, timestamp) TTL toDateTime(timestamp) + toIntervalSecond(345600) SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1
TAGS INNER COLUMNS
(
    `id` Tuple(UInt64, LowCardinality(UUID)) DEFAULT tuple(sipHash64(metric_name), toLowCardinality(reinterpretAsUUID(sipHash128(tags)))),
    `metric_name` LowCardinality(String),
    `tags` Map(LowCardinality(String), String),
    `min_time` SimpleAggregateFunction(min, Nullable(DateTime64(3))),
    `max_time` SimpleAggregateFunction(max, Nullable(DateTime64(3))),
    INDEX tags_idx tags TYPE text(tokenizer = 'keyValuePairs') GRANULARITY 100000000
)
TAGS INNER ENGINE = AggregatingMergeTree PRIMARY KEY metric_name ORDER BY (metric_name, id) SETTINGS allow_dimensions_outside_sorting_key = 1, index_granularity = 8192
METRIC FAMILIES INNER COLUMNS
(
    `metric_family_name` String,
    `type` LowCardinality(String),
    `unit` LowCardinality(String),
    `help` String
)
METRIC FAMILIES INNER ENGINE = ReplacingMergeTree ORDER BY metric_family_name
```

Es decir, las columnas se generaron automáticamente y además hay cuatro tablas internas de destino con sus propias definiciones de columnas
almacenadas en las cláusulas `INNER COLUMNS`. La opción `recent_samples_ttl_seconds` se escribió en la cláusula `SETTINGS`
con su valor predeterminado: la opción define el TTL de la tabla de muestras recientes, por lo que su valor efectivo queda fijado al crearla.
Además, la versión más reciente del esquema quedó fijada en la opción `version` (véase [Control de versiones del esquema](#schema-versioning)).

Las tablas internas de destino tienen nombres como `.inner_id.samples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
`.inner_id.recentsamples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, `.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
`.inner_id.metricfamilies.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
y cada tabla de destino tiene su propio conjunto de columnas:

```sql theme={null}
CREATE TABLE default.`.inner_id.samples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `id` Tuple(UInt64, LowCardinality(UUID)),
    `timestamp` DateTime64(3) CODEC(Delta(8), T64, ZSTD(3)),
    `value` Float64 CODEC(ALP, ZSTD(3))
)
ENGINE = MergeTree
ORDER BY (id, timestamp)
SETTINGS index_granularity = 32768
```

```sql theme={null}
CREATE TABLE default.`.inner_id.recentsamples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `id` Tuple(UInt64, UUID),
    `timestamp` DateTime64(3) CODEC(Delta(8), T64, ZSTD(3)),
    `value` Float64 CODEC(ALP, ZSTD(3))
)
ENGINE = MergeTree
PARTITION BY toStartOfInterval(toDateTime(timestamp), toIntervalHour(5))
ORDER BY (id, timestamp)
TTL toDateTime(timestamp) + toIntervalSecond(345600)
SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1
```

```sql theme={null}
CREATE TABLE default.`.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `id` Tuple(UInt64, LowCardinality(UUID)) DEFAULT tuple(sipHash64(metric_name), toLowCardinality(reinterpretAsUUID(sipHash128(tags)))),
    `metric_name` LowCardinality(String),
    `tags` Map(LowCardinality(String), String),
    `min_time` SimpleAggregateFunction(min, Nullable(DateTime64(3))),
    `max_time` SimpleAggregateFunction(max, Nullable(DateTime64(3))),
    INDEX tags_idx tags TYPE text(tokenizer = 'keyValuePairs') GRANULARITY 100000000
)
ENGINE = AggregatingMergeTree
PRIMARY KEY metric_name
ORDER BY (metric_name, id)
SETTINGS allow_dimensions_outside_sorting_key = 1, index_granularity = 8192
```

```sql theme={null}
CREATE TABLE default.`.inner_id.metricfamilies.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `metric_family_name` String,
    `type` LowCardinality(String),
    `unit` LowCardinality(String),
    `help` String
)
ENGINE = ReplacingMergeTree
ORDER BY metric_family_name
SETTINGS index_granularity = 8192
```

## Creación de una tabla AS a partir de una tabla existente

La sentencia `CREATE TABLE new_table AS existing_table` crea una tabla `TimeSeries` configurada como `existing_table`,
que debe ser una tabla `TimeSeries`. Los destinos externos de `existing_table` no se copian: la propia sentencia debe declarar
esos destinos.

La sentencia copia de `existing_table`:

* la cláusula `SETTINGS`, excepto `version`: la nueva tabla siempre obtiene la versión más reciente. Los ajustes especificados en la
  propia sentencia se combinan por nombre con los copiados, por lo que prevalece un ajuste especificado y `name = DEFAULT`
  restablece un ajuste copiado a su valor predeterminado;
* las cláusulas `INNER COLUMNS` e `INNER ENGINE` de cada tabla interna. Se conservan las columnas personalizadas (p. ej., columnas adicionales o columnas
  con un códec o una expresión DEFAULT) y las partes personalizadas del motor (p. ej., un motor con argumentos, una clave de ordenación personalizada
  o un ajuste del motor); las demás columnas y partes del motor se ajustan a los ajustes de la nueva tabla, de modo que
  p. ej., `tags_to_columns`, `aggregate_min_time_and_max_time` o `tags_index_granularity` especificadas en la sentencia surtan efecto.

Los tipos de las columnas `id`, de marca de tiempo y de valor, así como el tipo de replicación de los motores internos (`MergeTree`,
`ReplicatedMergeTree` o `SharedMergeTree`), también se toman de `existing_table`, a menos que la propia sentencia los declare.
La lista de columnas externas se vuelve a generar y no se copia.

Una tabla creada con una versión anterior de ClickHouse puede utilizarse como `existing_table`: la nueva tabla obtiene la
estructura actual, p. ej., el tipo actual de `id` y la expresión de identificador predeterminada.

## Ajuste de los tipos de las columnas

Puede ajustar los tipos de las columnas en las tablas internas de destino mediante la cláusula `INNER COLUMNS`. Por ejemplo, para almacenar marcas de tiempo en microsegundos y valores como `Float32`, use:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp DateTime64(6) CODEC(Delta, T64, ZSTD(3)), value Float32 CODEC(ALP, ZSTD(3)))
```

Especificar columnas internas sin códecs implica usar el códec predeterminado para ellas:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp DateTime64(6), value Float32)
```

## La columna `id`

La columna `id` contiene identificadores; cada uno se calcula a partir de una combinación de un nombre de métrica y etiquetas.
El tipo y la expresión `DEFAULT` utilizados para generar los identificadores se pueden personalizar mediante la cláusula `TAGS INNER COLUMNS`:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
TAGS INNER COLUMNS (id UInt64 DEFAULT sipHash64(tags))
```

La columna `id` puede ser de cualquier tipo comparable que no sea `Nullable`. Los tipos de `id` declarados en las tablas internas de samples y etiquetas deben coincidir.

Si no se proporciona ninguna expresión `DEFAULT` para la columna `id` y la configuración `id_generator` no está definida, ClickHouse elegirá automáticamente la expresión `DEFAULT` en función del tipo de `id`, pero solo si el tipo de `id` es uno de `UUID`, `UInt64`, `UInt128`, `FixedString(16)`, esos mismos tipos envueltos en `LowCardinality`, o una tupla de dos de esos tipos. Para dicha tupla, la expresión elegida automáticamente calcula un hash del nombre de la métrica en el primer componente y un hash de todas las etiquetas en el segundo componente.

Un tipo de identificador `LowCardinality`, por ejemplo `Tuple(UInt64, LowCardinality(UUID))`, mantiene los identificadores codificados mediante diccionario: la tabla de samples almacena pequeños diccionarios por bloque con índices de diccionario en lugar de repetir el identificador completo en cada fila, lo que reduce la cantidad de datos leídos por las consultas.

La configuración `id_generator` permite la misma personalización sin usar la cláusula `INNER COLUMNS`:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SETTINGS id_generator = 'sipHash64(tags)'
```

Si el ajuste está definido, se usa para generar `id` incluso si el `DEFAULT` de la columna contiene otra expresión.

El tipo de la columna `id` también se puede especificar en la configuración `id_type` en lugar de en la cláusula `INNER COLUMNS`:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SETTINGS id_type = 'UInt64', id_generator = 'sipHash64(tags)'
```

Cuando la configuración `id_generator` está definida, la configuración `id_type` se registra automáticamente en el momento del `CREATE`, de modo que la definición conserva el tipo para el que se escribió la expresión.

## La columna `tags`

La columna `tags` contiene todas las etiquetas de una serie temporal, incluida la etiqueta `__name__` con el nombre de una métrica.

La configuración `tags_to_columns` permite especificar que una etiqueta concreta también debe almacenarse en una columna independiente
además del mapa dentro de la columna `tags`:

```sql theme={null}
CREATE TABLE my_table
ENGINE = TimeSeries
SETTINGS tags_to_columns = {'instance': 'instance', 'job': 'job'}
```

Esta sentencia añadirá las columnas `instance` y `job` a la tabla de destino interna [etiquetas](#tags-table).
Los valores de las etiquetas `instance` y `job` se almacenarán tanto en esas columnas como en la columna `tags`.

<Note>
  En las tablas creadas con versiones anteriores de ClickHouse, la columna `tags` contiene solo las etiquetas, sin columnas específicas
  ni el nombre de la métrica, y la columna `all_tags` es una columna efímera que se rellenaba durante la inserción
  con todas las etiquetas excepto el nombre de la métrica.
</Note>

## Motores de las tablas internas de destino

De forma predeterminada, las tablas internas de destino usan los siguientes motores de tabla:

* la tabla [samples](#samples-table) usa [MergeTree](/es/reference/engines/table-engines/mergetree-family/mergetree);
* la tabla [muestras recientes](#recent-samples-table) usa [MergeTree](/es/reference/engines/table-engines/mergetree-family/mergetree) particionada en buckets de 5 horas (consulte la configuración [recent\_samples\_partition\_by](#settings)) con un `TTL` derivado de
  la configuración [recent\_samples\_ttl\_seconds](#settings) y con `ttl_only_drop_parts` habilitado, de modo que las partes expiradas se eliminan por completo;
* la tabla [etiquetas](#tags-table) usa [AggregatingMergeTree](/es/reference/engines/table-engines/mergetree-family/aggregatingmergetree) porque los mismos datos suelen insertarse varias veces en esta tabla, por lo que hace falta una forma
  de eliminar duplicados, y también porque es necesario realizar agregación para las columnas `min_time` y `max_time`;
* la tabla [familias de métricas](#metric-families-table) usa [ReplacingMergeTree](/es/reference/engines/table-engines/mergetree-family/replacingmergetree) porque los mismos datos suelen insertarse varias veces en esta tabla, por lo que hace falta una forma
  de eliminar duplicados.

La familia de motores de las tablas internas generadas sigue la configuración a nivel de consulta `default_table_engine`:
con `default_table_engine = ReplicatedMergeTree` o `SharedMergeTree`, las tablas internas usan los motores
`Replicated` o `Shared` correspondientes. Con `default_table_engine = None` (o cualquier otro valor), los motores de las tablas internas
deben especificarse explícitamente.

Todas las tablas internas deben tener el mismo tipo de replicación: si una de ellas está replicada (o compartida), las demás tablas
internas también deben estar replicadas (o compartidas); de lo contrario, su contenido divergiría entre réplicas. Por ejemplo,
declarar `SAMPLES INNER ENGINE = ReplicatedMergeTree(...)` requiere que los demás motores internos también estén replicados,
ya sea declarados explícitamente o generados con `default_table_engine = ReplicatedMergeTree`.

También se pueden usar otros motores de tabla para las tablas internas de destino si así se especifica:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES ENGINE=ReplicatedMergeTree
RECENT SAMPLES ENGINE=ReplicatedMergeTree
TAGS ENGINE=ReplicatedAggregatingMergeTree
METRIC FAMILIES ENGINE=ReplicatedReplacingMergeTree
```

La tabla [etiquetas](#tags-table) mantiene las columnas de etiquetas (y el Map `tags`) fuera de su clave de ordenación,
algo que `AggregatingMergeTree` rechaza de forma predeterminada (consulte [`allow_dimensions_outside_sorting_key`](/es/reference/engines/table-engines/mergetree-family/aggregatingmergetree)).
Esto es seguro aquí porque esas columnas dependen funcionalmente de `id`, que forma parte de la clave de ordenación, por lo que todas las
filas que un merge en segundo plano colapsa comparten los mismos valores. Cuando la tabla interna de etiquetas se genera o su
motor se especifica en línea como arriba, `TimeSeries` establece automáticamente `allow_dimensions_outside_sorting_key = 1` en ella;
para una tabla de etiquetas de agregación [externa](#external-target-tables) creada manualmente, debe configurarlo usted mismo.

## Tablas de destino externas

Es posible hacer que una tabla `TimeSeries` utilice una tabla creada manualmente:

```sql theme={null}
CREATE TABLE samples_for_my_table
(
    `id` UUID,
    `timestamp` DateTime64(3),
    `value` Float64
)
ENGINE = MergeTree
ORDER BY (id, timestamp);

CREATE TABLE tags_for_my_table ...

CREATE TABLE metric_families_for_my_table ...

CREATE TABLE my_table ENGINE=TimeSeries SAMPLES samples_for_my_table TAGS tags_for_my_table METRIC FAMILIES metric_families_for_my_table;
```

También se puede utilizar una tabla externa como destino de [muestra reciente](#recent-samples-table) (la cláusula `RECENT SAMPLES my_recent_samples_table`).
Dicha tabla debe tener las mismas columnas que una tabla externa de samples y debe conservar al menos
[recent\_samples\_ttl\_seconds](#settings) segundos de datos, lo cual es responsabilidad del usuario.

Los tipos de columna de las tablas externas (`id`, `timestamp`, `value` y las `<tag_value_column>` enumeradas en [`tags_to_columns`](#settings)) deben coincidir con los que la tabla `TimeSeries` generaría internamente en otras circunstancias (consulte [tabla Samples](#samples-table), [tabla Etiquetas](#tags-table) y [tabla Familias de métricas](#metric-families-table) para conocer las restricciones de tipo). Las discrepancias de tipo se notifican en el momento de `CREATE`.

El tipo de la columna `id` de una tabla externa de etiquetas y la expresión que genera los identificadores se registran en las configuraciones [`id_type`](#settings) e [`id_generator`](#settings) en el momento de `CREATE` (a partir de la [version](#schema-versioning) 2), de modo que la definición de la tabla `TimeSeries` los conserva: por ejemplo, `CREATE TABLE ... AS my_table` lee el tipo de `id` de la definición de `my_table` sin leer sus tablas de destino externas. Si no se especifica la configuración `id_generator`, se establece con el `DEFAULT` declarado en la columna `id` de la tabla externa (si existe) y, en caso contrario, con el generador canónico derivado del tipo de `id`. La expresión registrada se utiliza para generar `id` incluso si el `DEFAULT` de la tabla externa cambia posteriormente; consulte [La columna `id`](#id-column) para obtener más detalles.

## Modificar los ajustes

Se pueden modificar dos ajustes después de `CREATE`:

* `id_generator`
* `filter_by_min_time_and_max_time`

```sql theme={null}
ALTER TABLE my_table MODIFY SETTING id_generator = 'sipHash64(tags)';
ALTER TABLE my_table MODIFY SETTING filter_by_min_time_and_max_time = 0;
ALTER TABLE my_table RESET SETTING filter_by_min_time_and_max_time;
```

Ten en cuenta que cambiar `id_generator` cuando ya hay datos en la tabla de etiquetas puede generar IDs distintos para la misma combinación de métrica+etiqueta: las filas antiguas conservan sus IDs anteriores y las nuevas usan el nuevo generador.

Los demás ajustes no se pueden cambiar con `ALTER ... MODIFY SETTING`: la mayoría quedan incorporados en el esquema de las tablas internas en el momento de `CREATE`,
y el ajuste `version` se fija automáticamente en el momento de `CREATE` e identifica el propio esquema (consulta [Control de versiones del esquema](#schema-versioning)).

## Configuración

Aquí tienes una lista de configuraciones que se pueden especificar al definir una tabla `TimeSeries`:

| Nombre | Tipo | Predeterminado | Descripción |
| - | - | - | - |
| `id_type` | tipo de datos | depende de la columna `id` | El tipo de la columna `id` de las tablas de destino. Normalmente el tipo se declara en las cláusulas `INNER COLUMNS` de las tablas internas o en una tabla de etiquetas [externa](#external-target-tables); la configuración se registra automáticamente en el momento de `CREATE` si el tipo no se conserva de otro modo en la definición: si el destino de etiquetas es una tabla externa, o si la configuración `id_generator` está establecida. La configuración también puede especificarse explícitamente en lugar de `TAGS INNER COLUMNS (id <type>)`. Requiere que `version` sea al menos 2 |
| `id_generator` | Expresión | depende del tipo de `id` | Expresión que calcula el identificador (huella) de una serie temporal a partir de sus etiquetas. Si no se establece, se usa la expresión predeterminada para la columna `id`. Si la expresión predeterminada para la columna `id` tampoco está establecida, la expresión se elige automáticamente. Para una tabla externa de etiquetas, la configuración se registra automáticamente en el momento de `CREATE` si `version` es al menos 2 (consulta [Tablas de destino externas](#external-target-tables)) |
| `tags_to_columns` | Map | {} | Map que especifica qué etiquetas deben colocarse en columnas independientes en la tabla [etiquetas](#tags-table). Sintaxis: `{'tag1': 'column1', 'tag2' : column2, ...}` |
| `use_all_tags_column_to_generate_id` | Bool | false | Configuración obsoleta, no tiene ningún efecto |
| `store_min_time_and_max_time` | Bool | true | Si se establece en true, la tabla almacenará `min_time` y `max_time` para cada serie temporal |
| `aggregate_min_time_and_max_time` | Bool | true | Al crear una tabla `tags` interna de destino, esta opción permite usar `SimpleAggregateFunction(min, Nullable(DateTime64(3)))` en lugar de solo `Nullable(DateTime64(3))` como tipo de la columna `min_time`, y lo mismo para la columna `max_time` |
| `filter_by_min_time_and_max_time` | Bool | true | Si se establece en true, la tabla usará las columnas `min_time` y `max_time` para filtrar las series temporales |
| `samples_index_granularity` | UInt64 | 32768 | Establece `index_granularity` de la tabla [samples](#samples-table) interna. Cuando se establece explícitamente, sobrescribe `index_granularity` de la declaración del motor. Se ignora para una tabla externa de samples y un motor que no sea MergeTree |
| `recent_samples_ttl_seconds` | UInt64 | 345600 | Retención de la tabla de destino adicional `recent samples`, en la que también se escribe cada sample insertado. Una tabla interna de samples recientes siempre obtiene `TTL toDateTime(timestamp) + toIntervalSecond(recent_samples_ttl_seconds)` a partir de esta configuración (sobrescribiendo cualquier TTL de la declaración del motor); una tabla externa de samples recientes debe retener al menos esta cantidad de segundos de datos. Las consultas cuyo rango de tiempo cabe en la ventana de TTL prefieren la tabla de samples recientes a la tabla principal de samples (consulta la configuración de nivel de consulta `time_series_prefer_recent_samples_table`). El valor predeterminado es de 4 días; el valor efectivo queda fijado en la definición de la tabla en el momento de CREATE. Establécelo en 0 para deshabilitar la tabla de samples recientes |
| `recent_samples_partition_by` | Expression | `toStartOfInterval(toDateTime(timestamp), toIntervalHour(5))` | Clave de partición de la tabla interna `recent samples`, por ejemplo, `toStartOfHour(timestamp)`. Cuando se establece explícitamente, sobrescribe la clave de partición de la declaración del motor; si no se establece ninguna, se usa una partición por cada 5 horas. Se ignora para una tabla externa de samples recientes. Requiere que `recent_samples_ttl_seconds` sea distinto de cero |
| `recent_samples_index_granularity` | UInt64 | 8192 | Establece `index_granularity` de la tabla interna `recent samples`. Cuando se establece explícitamente, sobrescribe `index_granularity` de la declaración del motor. Se ignora para una tabla externa de samples recientes y un motor que no sea MergeTree. Requiere que `recent_samples_ttl_seconds` sea distinto de cero |
| `tags_index_granularity` | UInt64 | 8192 | Establece `index_granularity` de la tabla [etiquetas](#tags-table) interna. Cuando se establece explícitamente, sobrescribe `index_granularity` de la declaración del motor. Se ignora para una tabla externa de etiquetas y un motor que no sea MergeTree |
| `version` | UInt64 | 5 | La versión de la tabla: identifica el conjunto de tablas de destino y su estructura. La versión se fija automáticamente cuando se crea una tabla y no se puede cambiar posteriormente; normalmente debe omitirse en la consulta `CREATE TABLE` (consulta [Control de versiones del esquema](#schema-versioning)) |

## Control de versiones del esquema

El motor de tabla `TimeSeries` y la capa de ejecución de PromQL están en desarrollo activo:
el conjunto de tablas de destino y su estructura pueden cambiar entre versiones de ClickHouse.
Para que dichos cambios sean detectables, cada tabla `TimeSeries` almacena su versión en el SETTING [version](#settings).
La versión se fija automáticamente en la consulta `CREATE` al crear la tabla —su valor es la última versión conocida por el servidor (actualmente 5)—,
persiste en los metadatos de la tabla y no puede modificarse mediante `ALTER`. Las tablas creadas antes de que se introdujera el SETTING se consideran de versión 0.
Lo normal es omitir el SETTING en la consulta `CREATE TABLE`: así la tabla obtiene la última versión.
Se acepta un valor explícito de `version` siempre que el servidor admita esa versión; en ese caso la tabla se define tal como lo hace esa versión (consulte [Historial de versiones](#version-history)).
`CREATE TABLE ... AS other_table` no copia la versión de la otra tabla; consulte [Crear una tabla AS una tabla existente](#create-as).

Un servidor admite un rango de versiones, y la versión mínima puede variar según se trate de lectura con `SELECT`, de escritura con `INSERT`
o con el protocolo remote-write de Prometheus, o de evaluación de PromQL (las funciones de tabla [prometheusQuery](/es/reference/functions/table-functions/prometheusQuery),
[prometheusQueryRange](/es/reference/functions/table-functions/prometheusQueryRange)
y [timeSeriesSelector](/es/reference/functions/table-functions/timeSeriesSelector),
el dialecto `promql` y la API HTTP de consultas de Prometheus):

* Si la versión de una tabla `TimeSeries` es demasiado antigua para PromQL, se rechazan las consultas PromQL sobre ella. La excepción sugiere volver a crear la tabla:
  cree una nueva tabla `TimeSeries`, copie los datos con una consulta `INSERT ... SELECT` y sustituya la tabla antigua por la nueva.
* Si la versión es demasiado antigua para escribir en ella, se rechazan las consultas `INSERT` y el protocolo remote-write de Prometheus, mientras que las consultas `SELECT` siguen funcionando.
* Si la versión es demasiado antigua para el servidor en general, se rechaza cualquier consulta sobre la tabla (excepto `SHOW CREATE TABLE`, `DETACH` y `DROP`).

### Historial de versiones

| Versión | Cambios |
| - | - |
| 0 | Tablas creadas antes de que se introdujera el SETTING `version`, incluidas las tablas "prealpha" (que declaraban las columnas de las tablas de destino como [columnas externas](#outer-columns)) y las tablas sin la tabla de [muestras recientes](#recent-samples-table) |
| 1 | Se introdujo el SETTING `version` |
| 2 | Se introdujo el SETTING [`id_type`](#settings): una tabla con una tabla de etiquetas externa registra el tipo de la columna `id` en `id_type` y la expresión que genera los identificadores en [`id_generator`](#settings), de modo que su definición no depende de la tabla externa. `id_type` también se registra cuando se establece `id_generator` (véase [La columna `id`](#id-column)) |
| 3 | La columna externa `time_series` pasó a llamarse `samples` (véase [Columnas externas](#outer-columns)). Las tablas de versiones anteriores conservan el nombre antiguo de la columna, y las funciones de tabla [prometheusQuery](/es/reference/functions/table-functions/prometheusQuery) y [prometheusQueryRange](/es/reference/functions/table-functions/prometheusQueryRange) devuelven la columna con el nombre que utiliza la tabla. Los datos almacenados no cambiaron |
| 4 | La tabla de destino `metrics` pasó a llamarse `metric families`: la tabla interna se denomina `.inner_id.metricfamilies.<uuid>` en lugar de `.inner_id.metrics.<uuid>`, y la definición se escribe con la palabra clave `METRIC FAMILIES` en lugar de `METRICS`. Los datos almacenados no cambiaron |
| 5 | Las nuevas tablas de etiquetas internas con un motor de la familia `MergeTree` obtienen de forma predeterminada un índice de texto `keyValuePairs` sobre el mapa `tags` (véase [Tabla de etiquetas](#tags-table)) |

# Funciones

Aquí tienes una lista de funciones que admiten una tabla `TimeSeries` como argumento:

* [timeSeriesSamples](/es/reference/functions/table-functions/timeSeriesSamples)
* [timeSeriesTags](/es/reference/functions/table-functions/timeSeriesTags)
* [timeSeriesMetricFamilies](/es/reference/functions/table-functions/timeSeriesMetricFamilies)
